Confirmación de las cuentas y recuperación de contraseñas en ASP.NET Core
Por Rick Anderson, Ponant, y Joe Audette
Este tutorial muestra cómo crear una aplicación ASP.NET Core con confirmación de correo electrónico y restablecimiento de contraseña. Este tutorial no es un tema inicial. Debería estar familiarizado con lo siguiente:
Para obtener Blazor instrucciones, que agrega o reemplaza las instrucciones de este artículo, consulte los siguientes recursos:
Requisitos previos
- SDK de .NET Core 6.0 o versiones posteriores
- Se envió con éxito un correo electrónico correctamente desde una aplicación de consola de C#.
Creación y prueba de una aplicación web con autenticación
Ejecute los comandos siguientes para crear una aplicación web con autenticación.
dotnet new webapp -au Individual -o WebPWrecover
cd WebPWrecover
dotnet run
Registro de usuario con confirmación de correo electrónico simulado
Ejecute la aplicación, seleccione el vínculo Registrar y registre un usuario. Una vez registrado, se le redirigirá a la página a /Identity/Account/RegisterConfirmation
que contiene un vínculo para simular la confirmación por correo electrónico:
- Seleccione el vínculo
Click here to confirm your account
. - Seleccione el vínculo Inicio de sesión e inicie sesión con las mismas credenciales.
- Seleccione el
Hello YourEmail@provider.com!
vínculo, que redirige a la/Identity/Account/Manage/PersonalData
página. - Seleccione la pestaña Datos personales de la izquierda y, a continuación, seleccione Eliminar.
El Click here to confirm your account
vínculo se muestra porque un IEmailSender no se ha implementado y registrado con el contenedor de inserción de dependencias. Consulte el RegisterConfirmation
origen.
Nota:
Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, usa la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, vea Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Configuración de un proveedor de correo electrónico
En este tutorial, SendGrid se usa para enviar correo electrónico. Se necesita una cuenta y una clave de SendGrid para enviar correo electrónico. Se recomienda usar SendGrid u otro servicio de correo electrónico para enviar correo electrónico en lugar de SMTP. SMTP es difícil de proteger y configurar correctamente.
La cuenta de SendGrid puede requerir agregar un remitente.
Cree una clase para capturar la clave de correo electrónico segura. Para este ejemplo, cree Services/AuthMessageSenderOptions.cs
:
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
Configuración de secretos de usuario de SendGrid
Configure el SendGridKey
con laherramienta administrador de secretos. Por ejemplo:
dotnet user-secrets set SendGridKey <key>
Successfully saved SendGridKey to the secret store.
En Windows, Secret Manager almacena pares de claves y valor en un secrets.json
archivo del %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId>
directorio.
El contenido del secrets.json
archivo no está cifrado. El siguiente marcado muestra el archivo secrets.json
. El valor SendGridKey
fue retirado.
{
"SendGridKey": "<key removed>"
}
Para más información, consulte el patrón Opciones y configuración.
Instalación de SendGrid
En este tutorial se muestra cómo agregar notificaciones por correo electrónico a través de SendGrid, pero se pueden usar otros proveedores de correo electrónico.
Instale el paquete NuGet SendGrid
:
En la consola del gestor de paquetes, introduzca el siguiente comando:
Install-Package SendGrid
Consulte Introducción a SendGrid gratis para registrarse para obtener una cuenta gratuita de SendGrid.
Implementar IEmailSender
Para implementar IEmailSender
, cree Services/EmailSender.cs
con código similar al siguiente:
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using SendGrid;
using SendGrid.Helpers.Mail;
namespace WebPWrecover.Services;
public class EmailSender : IEmailSender
{
private readonly ILogger _logger;
public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
ILogger<EmailSender> logger)
{
Options = optionsAccessor.Value;
_logger = logger;
}
public AuthMessageSenderOptions Options { get; } //Set with Secret Manager.
public async Task SendEmailAsync(string toEmail, string subject, string message)
{
if (string.IsNullOrEmpty(Options.SendGridKey))
{
throw new Exception("Null SendGridKey");
}
await Execute(Options.SendGridKey, subject, message, toEmail);
}
public async Task Execute(string apiKey, string subject, string message, string toEmail)
{
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("Joe@contoso.com", "Password Recovery"),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(toEmail));
// Disable click tracking.
// See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
msg.SetClickTracking(false, false);
var response = await client.SendEmailAsync(msg);
_logger.LogInformation(response.IsSuccessStatusCode
? $"Email to {toEmail} queued successfully!"
: $"Failure Email to {toEmail}");
}
}
Configuración de la aplicación para admitir correo electrónico
Agregue el siguiente código al archivo Program.cs
:
- Agregue
EmailSender
como un servicio transitorio. - Registre la instancia de configuración
AuthMessageSenderOptions
.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Deshabilite la comprobación predeterminada de la cuenta cuando account.RegisterConfirmation se haya aplicado scaffolding
Esta sección solo se aplica cuando Account.RegisterConfirmation
se aplica scaffolding. Omita esta sección si no ha aplicado scaffolding a Account.RegisterConfirmation
.
Se redirige al usuario al Account.RegisterConfirmation
donde puede seleccionar un vínculo para que se confirme la cuenta. El Account.RegisterConfirmation
predeterminado se usa solo para pruebas, la verificación automática de cuentas debería estar desactivada en una aplicación de producción.
Para requerir una cuenta confirmada e impedir el inicio de sesión inmediato en el registro, establezca DisplayConfirmAccountLink = false
en el archivo /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
al que se le ha aplicado scaffolding:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace WebPWrecover.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly IEmailSender _sender;
public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
{
_userManager = userManager;
_sender = sender;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string Email { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public bool DisplayConfirmAccountLink { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string EmailConfirmationUrl { get; set; }
public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
{
if (email == null)
{
return RedirectToPage("/Index");
}
returnUrl = returnUrl ?? Url.Content("~/");
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
return NotFound($"Unable to load user with email '{email}'.");
}
Email = email;
// Once you add a real email sender, you should remove this code that lets you confirm the account
DisplayConfirmAccountLink = false;
if (DisplayConfirmAccountLink)
{
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
EmailConfirmationUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
}
return Page();
}
}
}
Este paso solo es necesario cuando Account.RegisterConfirmation
se aplica scaffolding. RegisterConfirmation no con scaffolding detecta automáticamente cuándo se ha implementado un IEmailSender y se ha registrado con el contenedor de inserción de dependencias.
Registro, confirmación de correo electrónico y restablecimiento de contraseña
Ejecute la aplicación web y pruebe el flujo de confirmación de la cuenta y recuperación de contraseñas.
- Ejecute la aplicación y registre un usuario nuevo
- Compruebe el correo electrónico del vínculo de confirmación de la cuenta. Consulte Depurar correo electrónico si no recibe el correo electrónico.
- Haga clic en el vínculo para confirmar el correo electrónico.
- Inicio de sesión con la dirección de correo electrónico y la contraseña.
- Cierre la sesión.
Prueba del restablecimiento de contraseña
- Si ha iniciado sesión, seleccione Cerrar sesión.
- Seleccione el vínculo Iniciar sesión y seleccione el vínculo ¿Olvidó la contraseña?
- Escriba el correo electrónico que usó para registrar la cuenta.
- Se envía un correo electrónico con un vínculo para restablecer la contraseña. Compruebe el correo electrónico y haga clic en el vínculo para restablecer la contraseña. Una vez que la contraseña se haya restablecido correctamente, puede iniciar sesión con el correo electrónico y la nueva contraseña.
Reenviar confirmación por correo electrónico
Seleccione el vínculo Reenviar confirmación por correo electrónico en la página Inicio de sesión.
Cambio del tiempo de espera de correo electrónico y actividad
El tiempo de inactividad por defecto es de 14 días. El código siguiente establece el tiempo de espera de inactividad en 5 días:
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
builder.Services.ConfigureApplicationCookie(o => {
o.ExpireTimeSpan = TimeSpan.FromDays(5);
o.SlidingExpiration = true;
});
var app = builder.Build();
// Code removed for brevity
Cambio de toda la duración del token de protección de datos
El código siguiente cambia el período de tiempo de espera de todos los tokens de protección de datos a 3 horas:
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
builder.Services.Configure<DataProtectionTokenProviderOptions>(o =>
o.TokenLifespan = TimeSpan.FromHours(3));
var app = builder.Build();
// Code removed for brevity.
Los tokens de usuario integrados Identity (consulte AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs )tienen un tiempo de espera de un día.
Cambiar la duración del token de correo electrónico
La duración predeterminada del token de los Identity tokens de usuario es un día. En esta sección se muestra cómo cambiar la duración del token de correo electrónico.
Agregar un DataProtectorTokenProvider<TUser> y DataProtectionTokenProviderOptions personalizado:
public class CustomEmailConfirmationTokenProvider<TUser>
: DataProtectorTokenProvider<TUser> where TUser : class
{
public CustomEmailConfirmationTokenProvider(
IDataProtectionProvider dataProtectionProvider,
IOptions<EmailConfirmationTokenProviderOptions> options,
ILogger<DataProtectorTokenProvider<TUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
{
public EmailConfirmationTokenProviderOptions()
{
Name = "EmailDataProtectorTokenProvider";
TokenLifespan = TimeSpan.FromHours(4);
}
}
Agregue el proveedor personalizado al contenedor de servicios:
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
using WebPWrecover.TokenProviders;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
config.Tokens.ProviderMap.Add("CustomEmailConfirmation",
new TokenProviderDescriptor(
typeof(CustomEmailConfirmationTokenProvider<IdentityUser>)));
config.Tokens.EmailConfirmationTokenProvider = "CustomEmailConfirmation";
}).AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddTransient<CustomEmailConfirmationTokenProvider<IdentityUser>>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
var app = builder.Build();
// Code removed for brevity.
Depurar correo electrónico
Si no puede obtener el correo electrónico funcionando:
- Establezca un punto de interrupción en
EmailSender.Execute
para comprobar que se llama aSendGridClient.SendEmailAsync
. - Cree una aplicación de consola para enviar correo electrónico con código similar a
EmailSender.Execute
. - Revise la página actividad de Email.
- Compruebe la carpeta de correo no deseado.
- Pruebe otro alias de correo electrónico en otro proveedor de correo electrónico (Microsoft, Yahoo, Gmail, etc.)
- Intente enviar a diferentes cuentas de correo electrónico.
Un procedimiento recomendado de seguridad es no usar secretos de producción en pruebas y desarrollo. Si publica la aplicación en Azure, establezca los secretos de SendGrid como configuración de la aplicación en el portal de Azure Web App. El sistema de configuración se configura para leer las claves de las variables de entorno.
Combinar cuentas de inicio de sesión locales y sociales
Para completar esta sección, primero debe habilitar un proveedor de autenticación externo. Véase Autenticación de Facebook, Google y proveedores externos.
Puede combinar cuentas locales y sociales haciendo clic en el vínculo de correo electrónico. En la siguiente secuencia, "RickAndMSFT@gmail.com" se crea primero como inicio de sesión local; sin embargo, puede crear la cuenta como inicio de sesión social primero y, a continuación, agregar un inicio de sesión local.
Haga clic en el vínculo Administrar. Tenga en cuenta el 0 externo (inicios de sesión sociales) asociados a esta cuenta.
Haga clic en el vínculo a otro servicio de inicio de sesión y acepte las solicitudes de la aplicación. En la imagen siguiente, Facebook es el proveedor de autenticación externo:
Se han combinado las dos cuentas. Puede iniciar sesión con cualquiera de las cuentas. Es posible que quiera que los usuarios agreguen cuentas locales en caso de que su servicio de autenticación de inicio de sesión social esté inactivo o que haya perdido el acceso a su cuenta social.
Habilitación de la confirmación de la cuenta después de que un sitio tenga usuarios
Habilitar la confirmación de la cuenta en un sitio con usuarios bloquea todos los usuarios existentes. Los usuarios existentes están bloqueados porque sus cuentas no están confirmadas. Para solucionar el bloqueo de usuario existente, use uno de los métodos siguientes:
- Actualice la base de datos para marcar todos los usuarios existentes como confirmados.
- Confirme los usuarios existentes. Por ejemplo, los correos electrónicos de envío por lotes con vínculos de confirmación.
Prerrequisitos
SDK de .NET Core 3.0 o versiones posteriores
Creación y prueba de una aplicación web con autenticación
Ejecute los comandos siguientes para crear una aplicación web con autenticación.
dotnet new webapp -au Individual -uld -o WebPWrecover
cd WebPWrecover
dotnet run
Ejecute la aplicación, seleccione el vínculo Registrar y registre un usuario. Una vez registrado, se le redirigirá a la página a /Identity/Account/RegisterConfirmation
que contiene un vínculo para simular la confirmación por correo electrónico:
- Seleccione el vínculo
Click here to confirm your account
. - Seleccione el vínculo Inicio de sesión e inicie sesión con las mismas credenciales.
- Seleccione el
Hello YourEmail@provider.com!
vínculo, que redirige a la/Identity/Account/Manage/PersonalData
página. - Seleccione la pestaña Datos personales de la izquierda y, a continuación, seleccione Eliminar.
Configuración de un proveedor de correo electrónico
En este tutorial, SendGrid se usa para enviar correo electrónico. Puede usar otros proveedores de correo electrónico. Se recomienda usar SendGrid u otro servicio de correo electrónico para enviar correo electrónico. SMTP es difícil de configurar, por lo que el correo no está marcado como correo no deseado.
La cuenta de SendGrid puede requerir agregar un remitente.
Cree una clase para capturar la clave de correo electrónico segura. Para este ejemplo, cree Services/AuthMessageSenderOptions.cs
:
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
Configuración de secretos de usuario de SendGrid
Configure el SendGridKey
con laherramienta administrador de secretos. Por ejemplo:
dotnet user-secrets set SendGridKey <SG.key>
Successfully saved SendGridKey = SG.keyVal to the secret store.
En Windows, Secret Manager almacena pares de claves y valor en un secrets.json
archivo del %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId>
directorio.
El contenido del secrets.json
archivo no está cifrado. El siguiente marcado muestra el archivo secrets.json
. El valor SendGridKey
fue retirado.
{
"SendGridKey": "<key removed>"
}
Para más información, consulte el patrón Opciones y configuración.
Instalación de SendGrid
En este tutorial se muestra cómo agregar notificaciones por correo electrónico a través de SendGrid, pero puede enviar correo electrónico mediante SMTP y otros mecanismos.
Instale el paquete NuGet SendGrid
:
En la consola del gestor de paquetes, introduzca el siguiente comando:
Install-Package SendGrid
Consulte Introducción a SendGrid gratis para registrarse para obtener una cuenta gratuita de SendGrid.
Implementar IEmailSender
Para implementar IEmailSender
, cree Services/EmailSender.cs
con código similar al siguiente:
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using SendGrid;
using SendGrid.Helpers.Mail;
namespace WebPWrecover.Services;
public class EmailSender : IEmailSender
{
private readonly ILogger _logger;
public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
ILogger<EmailSender> logger)
{
Options = optionsAccessor.Value;
_logger = logger;
}
public AuthMessageSenderOptions Options { get; } //Set with Secret Manager.
public async Task SendEmailAsync(string toEmail, string subject, string message)
{
if (string.IsNullOrEmpty(Options.SendGridKey))
{
throw new Exception("Null SendGridKey");
}
await Execute(Options.SendGridKey, subject, message, toEmail);
}
public async Task Execute(string apiKey, string subject, string message, string toEmail)
{
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("Joe@contoso.com", "Password Recovery"),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(toEmail));
// Disable click tracking.
// See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
msg.SetClickTracking(false, false);
var response = await client.SendEmailAsync(msg);
_logger.LogInformation(response.IsSuccessStatusCode
? $"Email to {toEmail} queued successfully!"
: $"Failure Email to {toEmail}");
}
}
Configuración de la aplicación para admitir correo electrónico
Agregue el código siguiente al ConfigureServices
método en el archivo Startup.cs
:
- Agregue
EmailSender
como un servicio transitorio. - Registre la instancia de configuración
AuthMessageSenderOptions
.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
RegisterConfirmation del scaffolding
Siga las instrucciones de Scaffold Identity y scaffold Account\RegisterConfirmation
.
Deshabilite la comprobación predeterminada de la cuenta cuando account.RegisterConfirmation se haya aplicado scaffolding
Esta sección solo se aplica cuando Account.RegisterConfirmation
se aplica scaffolding. Omita esta sección si no ha aplicado scaffolding a Account.RegisterConfirmation
.
Se redirige al usuario al Account.RegisterConfirmation
donde puede seleccionar un vínculo para que se confirme la cuenta. El Account.RegisterConfirmation
predeterminado se usa solo para pruebas, la verificación automática de cuentas debería estar desactivada en una aplicación de producción.
Para requerir una cuenta confirmada e impedir el inicio de sesión inmediato en el registro, establezca DisplayConfirmAccountLink = false
en el archivo /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
al que se le ha aplicado scaffolding:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace WebPWrecover.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly IEmailSender _sender;
public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
{
_userManager = userManager;
_sender = sender;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string Email { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public bool DisplayConfirmAccountLink { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string EmailConfirmationUrl { get; set; }
public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
{
if (email == null)
{
return RedirectToPage("/Index");
}
returnUrl = returnUrl ?? Url.Content("~/");
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
return NotFound($"Unable to load user with email '{email}'.");
}
Email = email;
// Once you add a real email sender, you should remove this code that lets you confirm the account
DisplayConfirmAccountLink = false;
if (DisplayConfirmAccountLink)
{
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
EmailConfirmationUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
}
return Page();
}
}
}
Este paso solo es necesario cuando Account.RegisterConfirmation
se aplica scaffolding. RegisterConfirmation no con scaffolding detecta automáticamente cuándo se ha implementado un IEmailSender y se ha registrado con el contenedor de inserción de dependencias.
Registro, confirmación de correo electrónico y restablecimiento de contraseña
Ejecute la aplicación web y pruebe el flujo de confirmación de la cuenta y recuperación de contraseñas.
- Ejecute la aplicación y registre un usuario nuevo
- Compruebe el correo electrónico del vínculo de confirmación de la cuenta. Consulte Depurar correo electrónico si no recibe el correo electrónico.
- Haga clic en el vínculo para confirmar el correo electrónico.
- Inicio de sesión con la dirección de correo electrónico y la contraseña.
- Cierre la sesión.
Prueba del restablecimiento de contraseña
- Si ha iniciado sesión, seleccione Cerrar sesión.
- Seleccione el vínculo Iniciar sesión y seleccione el vínculo ¿Olvidó la contraseña?
- Escriba el correo electrónico que usó para registrar la cuenta.
- Se envía un correo electrónico con un vínculo para restablecer la contraseña. Compruebe el correo electrónico y haga clic en el vínculo para restablecer la contraseña. Una vez que la contraseña se haya restablecido correctamente, puede iniciar sesión con el correo electrónico y la nueva contraseña.
Reenviar confirmación por correo electrónico
En ASP.NET Core 5.0 y versiones posteriores, seleccione el vínculo Reenviar confirmación de correo electrónico en la página Inicio de sesión.
Cambio del tiempo de espera de correo electrónico y actividad
El tiempo de inactividad por defecto es de 14 días. El código siguiente establece el tiempo de espera de inactividad en 5 días:
services.ConfigureApplicationCookie(o => {
o.ExpireTimeSpan = TimeSpan.FromDays(5);
o.SlidingExpiration = true;
});
Cambio de toda la duración del token de protección de datos
El código siguiente cambia el período de tiempo de espera de todos los tokens de protección de datos a 3 horas:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.Configure<DataProtectionTokenProviderOptions>(o =>
o.TokenLifespan = TimeSpan.FromHours(3));
services.AddTransient<IEmailSender, EmailSender>();
services.Configure<AuthMessageSenderOptions>(Configuration);
services.AddRazorPages();
}
Los tokens de usuario integrados Identity (consulte AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs )tienen un tiempo de espera de un día.
Cambiar la duración del token de correo electrónico
La duración predeterminada del token de los Identity tokens de usuario es un día. En esta sección se muestra cómo cambiar la duración del token de correo electrónico.
Agregar un DataProtectorTokenProvider<TUser> y DataProtectionTokenProviderOptions personalizado:
public class CustomEmailConfirmationTokenProvider<TUser>
: DataProtectorTokenProvider<TUser> where TUser : class
{
public CustomEmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
IOptions<EmailConfirmationTokenProviderOptions> options,
ILogger<DataProtectorTokenProvider<TUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
{
public EmailConfirmationTokenProviderOptions()
{
Name = "EmailDataProtectorTokenProvider";
TokenLifespan = TimeSpan.FromHours(4);
}
}
Agregue el proveedor personalizado al contenedor de servicios:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
config.Tokens.ProviderMap.Add("CustomEmailConfirmation",
new TokenProviderDescriptor(
typeof(CustomEmailConfirmationTokenProvider<IdentityUser>)));
config.Tokens.EmailConfirmationTokenProvider = "CustomEmailConfirmation";
}).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddTransient<CustomEmailConfirmationTokenProvider<IdentityUser>>();
services.AddTransient<IEmailSender, EmailSender>();
services.Configure<AuthMessageSenderOptions>(Configuration);
services.AddRazorPages();
}
Depurar correo electrónico
Si no puede obtener el correo electrónico funcionando:
- Establezca un punto de interrupción en
EmailSender.Execute
para comprobar que se llama aSendGridClient.SendEmailAsync
. - Cree una aplicación de consola para enviar correo electrónico con código similar a
EmailSender.Execute
. - Revise la página actividad de Email.
- Compruebe la carpeta de correo no deseado.
- Pruebe otro alias de correo electrónico en otro proveedor de correo electrónico (Microsoft, Yahoo, Gmail, etc.)
- Intente enviar a diferentes cuentas de correo electrónico.
Un procedimiento recomendado de seguridad es no usar secretos de producción en pruebas y desarrollo. Si publica la aplicación en Azure, establezca los secretos de SendGrid como configuración de la aplicación en el portal de Azure Web App. El sistema de configuración se configura para leer las claves de las variables de entorno.
Combinar cuentas de inicio de sesión locales y sociales
Para completar esta sección, primero debe habilitar un proveedor de autenticación externo. Véase Autenticación de Facebook, Google y proveedores externos.
Puede combinar cuentas locales y sociales haciendo clic en el vínculo de correo electrónico. En la siguiente secuencia, "RickAndMSFT@gmail.com" se crea primero como inicio de sesión local; sin embargo, puede crear la cuenta como inicio de sesión social primero y, a continuación, agregar un inicio de sesión local.
Haga clic en el vínculo Administrar. Tenga en cuenta el 0 externo (inicios de sesión sociales) asociados a esta cuenta.
Haga clic en el vínculo a otro servicio de inicio de sesión y acepte las solicitudes de la aplicación. En la imagen siguiente, Facebook es el proveedor de autenticación externo:
Se han combinado las dos cuentas. Puede iniciar sesión con cualquiera de las cuentas. Es posible que quiera que los usuarios agreguen cuentas locales en caso de que su servicio de autenticación de inicio de sesión social esté inactivo o que haya perdido el acceso a su cuenta social.
Habilitación de la confirmación de la cuenta después de que un sitio tenga usuarios
Habilitar la confirmación de la cuenta en un sitio con usuarios bloquea todos los usuarios existentes. Los usuarios existentes están bloqueados porque sus cuentas no están confirmadas. Para solucionar el bloqueo de usuario existente, use uno de los métodos siguientes:
- Actualice la base de datos para marcar todos los usuarios existentes como confirmados.
- Confirme los usuarios existentes. Por ejemplo, los correos electrónicos de envío por lotes con vínculos de confirmación.