Confirmação de conta e de recuperação de senha no ASP.NET Core
Por Rick Anderson, Ponant e Joe Audette
Esse tutorial mostra como criar um aplicativo ASP.NET Core com confirmação por email e redefinição de senha. Este tutorial não é um tópico inicial. Você deve estar familiarizado com:
Para consultar as diretrizes do Blazor, que adicionam ou se sobrepõem às diretrizes deste artigo, consulte Confirmação de conta e recuperação de senha no ASP.NET Core Blazor.
Pré-requisitos
Criar e testar um aplicativo Web com autenticação
Execute os comandos a seguir para criar um aplicativo Web com autenticação.
dotnet new webapp -au Individual -o WebPWrecover
cd WebPWrecover
dotnet run
Registrar usuário com confirmação de email simulado
Execute o aplicativo, selecione o link Registrar e registre um usuário. Depois de registrado, você será redirecionado para a página /Identity/Account/RegisterConfirmation
, que contém um link para simular a confirmação por email:
- Selecione o link
Click here to confirm your account
. - Selecione o link Fazer logon e entre com as mesmas credenciais.
- Selecione o link
Hello YourEmail@provider.com!
, que redireciona para a página/Identity/Account/Manage/PersonalData
. - Selecione a guia Dados pessoais à esquerda e, em seguida, selecione Excluir.
O link Click here to confirm your account
é exibido porque um IEmailSender não foi implementado e registrado com o contêiner de injeção de dependência. Consulte a fonte de RegisterConfirmation
.
Observação
Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Configurar um provedor de email
Neste tutorial, o SendGrid é usado para enviar email. Uma conta do SendGrid e uma chave são necessárias para enviar emails. É recomendável usar o SendGrid ou outro serviço de email para enviar email em vez de SMTP. O SMTP é difícil de proteger e configurar corretamente.
A conta do SendGrid pode exigir a adição de um Remetente.
Crie uma classe para buscar a chave de email segura. Para este exemplo, crie Services/AuthMessageSenderOptions.cs
:
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
Configurar segredos do usuário do SendGrid
Defina o SendGridKey
com a ferramenta Secret Manager. Por exemplo:
dotnet user-secrets set SendGridKey <key>
Successfully saved SendGridKey to the secret store.
No Windows, o Secret Manager armazena pares de chave/valor em um arquivo secrets.json
no diretório %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId>
.
O conteúdo do arquivo secrets.json
não é criptografado. A seguinte marcação mostra o arquivo secrets.json
. O valor de SendGridKey
foi removido.
{
"SendGridKey": "<key removed>"
}
Para obter mais informações, consulte o padrão de Opções e configuração.
Instalar o SendGrid
Esse tutorial mostra como adicionar notificações por email por meio do SendGrid, mas outros provedores de email podem ser usados.
Instale o pacote SendGrid
do NuGet.
No Console do Gerenciador de Pacotes, insira o seguinte comando:
Install-Package SendGrid
Confira Introdução ao SendGrid gratuito para se registrar em uma conta gratuita do SendGrid.
Implementar o IEmailSender
Para implementar o IEmailSender
, crie Services/EmailSender.cs
com o código semelhante ao seguinte:
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}");
}
}
Configurar o aplicativo para dar suporte ao email
Adicione o seguinte código ao arquivo Program.cs
:
- Adicione o
EmailSender
como um serviço transitório. - Registre a instância de configuração
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();
Desabilitar a verificação de conta padrão quando Account.RegisterConfirmation tiver sido gerado por scaffolding
Esta seção só se aplica quando Account.RegisterConfirmation
é gerado por scaffolding. Ignore esta seção se você não tiver gerado Account.RegisterConfirmation
por scaffolding.
O usuário é redirecionado para a Account.RegisterConfirmation
, no qual pode selecionar um link para que a conta seja confirmada. O padrão Account.RegisterConfirmation
é usado apenas para teste. A verificação automática de conta deve ser desabilitada em um aplicativo de produção.
Para exigir uma conta confirmada e impedir o logon imediato durante o registro, defina DisplayConfirmAccountLink = false
no arquivo /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
gerado por 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();
}
}
}
Essa etapa só é necessária quando Account.RegisterConfirmation
é gerado por scaffolding. O RegisterConfirmation não gerado por scaffolding detecta automaticamente quando um IEmailSender foi implementado e registrado com o contêiner de injeção de dependência.
Registrar, confirmar email e redefinir senha
Execute o aplicativo Web e teste o fluxo de confirmação e recuperação de senha da conta.
- Execute o aplicativo e registre um novo usuário
- Verifique seu email para obter o link de confirmação da conta. Consulte Depurar email se você não receber o email.
- Clique no link para confirmar seu email.
- Entre com o endereço de email e senha.
- Saia.
Testar redefinição de senha
- Se você estiver conectado, selecione Sair.
- Selecione o link Fazer logon e selecione o link Esqueceu sua senha?.
- Insira o email que você usou para registrar a conta.
- Um email com um link para redefinir sua senha é enviado. Verifique seu email e clique no link para redefinir sua senha. Depois que sua senha tiver sido redefinida com sucesso, você poderá entrar com seu email e a nova senha.
Reenviar confirmação de email
Selecione o link Reenviar confirmação de email na página Fazer logon.
Alterar o tempo limite de email e de atividade
O tempo limite de inatividade padrão é de 14 dias. O código a seguir define o tempo limite de inatividade como 5 dias:
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
Alterar todos os tempos de vida do token de proteção de dados
O código a seguir altera o tempo limite de todos os tokens de proteção de dados para 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.
Os tokens internos de usuário Identity (consulte AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs) têm um tempo limite de um dia.
Alterar o tempo de vida do token de email
O tempo de vida do token padrão dos tokens Identity de usuário é de um dia. Esta seção mostra como alterar o tempo de vida do token de email.
Adicionar um DataProtectorTokenProvider<TUser> e 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);
}
}
Adicione o provedor personalizado ao contêiner de serviço:
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 email
Se você não conseguir usar o email:
- Defina um ponto de interrupção em
EmailSender.Execute
para verificar seSendGridClient.SendEmailAsync
é chamado. - Crie um aplicativo de console para enviar emails usando um código semelhante a
EmailSender.Execute
. - Examine a página Atividade de Email.
- Verifique sua pasta de spam.
- Experimente outro alias de email em um provedor de email diferente (Microsoft, Yahoo, Gmail etc.)
- Tente enviar para contas de email diferentes.
A melhor prática de segurança é não usar segredos de produção em ambiente de teste e de desenvolvimento. Se você publicar o aplicativo no Azure, defina os segredos do SendGrid como configurações de aplicativo no portal do Aplicativo Web do Azure. O sistema de configuração é definido para ler chaves de variáveis de ambiente.
Combinar contas de logon sociais e locais
Para concluir esta seção, primeiro você deve habilitar um provedor externo de autenticação. Consulte Autenticação do Facebook, Google e de provedor externo.
Você pode combinar contas locais e sociais clicando em seu link de email. Na sequência a seguir, “RickAndMSFT@gmail.com” é criado primeiro como um logon local. No entanto, você pode criar a conta como logon social primeiro e, em seguida, adicionar um logon local.
Clique no link Gerenciar. Observe 0 (logon social) externo associado a essa conta.
Clique no link para outro serviço de logon e aceite as solicitações do aplicativo. Na imagem a seguir, o Facebook é o provedor externo de autenticação:
As duas contas foram combinadas. Você pode fazer logon com qualquer conta. Talvez você queira que os usuários adicionem contas locais caso o serviço de autenticação de logon social esteja inativo ou provavelmente eles tenham perdido o acesso à conta social.
Habilitar a confirmação da conta depois que um site tiver usuários
Habilitar a confirmação da conta em um site com usuários bloqueia todos os usuários existentes. Os usuários existentes são bloqueados porque suas contas não foram confirmadas. Para contornar o bloqueio de usuário existente, use uma das seguintes abordagens:
- Atualize o banco de dados para marcar todos os usuários existentes como sendo confirmados.
- Confirme os usuários existentes. Por exemplo, enviar emails em lote com links de confirmação.
Pré-requisitos
SDK do .NET Core 3.0 ou posterior
Criar e testar um aplicativo Web com autenticação
Execute os comandos a seguir para criar um aplicativo Web com autenticação.
dotnet new webapp -au Individual -uld -o WebPWrecover
cd WebPWrecover
dotnet run
Execute o aplicativo, selecione o link Registrar e registre um usuário. Depois de registrado, você será redirecionado para a página /Identity/Account/RegisterConfirmation
, que contém um link para simular a confirmação por email:
- Selecione o link
Click here to confirm your account
. - Selecione o link Fazer logon e entre com as mesmas credenciais.
- Selecione o link
Hello YourEmail@provider.com!
, que redireciona para a página/Identity/Account/Manage/PersonalData
. - Selecione a guia Dados pessoais à esquerda e, em seguida, selecione Excluir.
Configurar um provedor de email
Neste tutorial, o SendGrid é usado para enviar email. Você pode usar outros provedores de email. Recomendamos usar o SendGrid ou outro serviço de email para enviar emails. É difícil configurar o SMTP para que o email não seja marcado como spam.
A conta do SendGrid pode exigir a adição de um Remetente.
Crie uma classe para buscar a chave de email segura. Para este exemplo, crie Services/AuthMessageSenderOptions.cs
:
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
Configurar segredos do usuário do SendGrid
Defina o SendGridKey
com a ferramenta Secret Manager. Por exemplo:
dotnet user-secrets set SendGridKey <SG.key>
Successfully saved SendGridKey = SG.keyVal to the secret store.
No Windows, o Secret Manager armazena pares de chave/valor em um arquivo secrets.json
no diretório %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId>
.
O conteúdo do arquivo secrets.json
não é criptografado. A seguinte marcação mostra o arquivo secrets.json
. O valor de SendGridKey
foi removido.
{
"SendGridKey": "<key removed>"
}
Para obter mais informações, consulte o padrão de Opções e configuração.
Instalar o SendGrid
Este tutorial mostra como adicionar notificações por email através do SendGrid, mas você pode enviar emails usando o SMTP e outros mecanismos.
Instale o pacote SendGrid
do NuGet.
No Console do Gerenciador de Pacotes, insira o seguinte comando:
Install-Package SendGrid
Confira Introdução ao SendGrid gratuito para se registrar em uma conta gratuita do SendGrid.
Implementar o IEmailSender
Para implementar o IEmailSender
, crie Services/EmailSender.cs
com o código semelhante ao seguinte:
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}");
}
}
Configurar a inicialização para dar suporte ao email
Adicione o seguinte código ao método ConfigureServices
no arquivo Startup.cs
:
- Adicione o
EmailSender
como um serviço transitório. - Registre a instância de configuração
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();
Fazer scaffolding de RegisterConfirmation
Siga as instruções para Fazer scaffolding de Identity e fazer scaffolding de Account\RegisterConfirmation
.
Desabilitar a verificação de conta padrão quando Account.RegisterConfirmation tiver sido gerado por scaffolding
Esta seção só se aplica quando Account.RegisterConfirmation
é gerado por scaffolding. Ignore esta seção se você não tiver gerado Account.RegisterConfirmation
por scaffolding.
O usuário é redirecionado para a Account.RegisterConfirmation
, no qual pode selecionar um link para que a conta seja confirmada. O padrão Account.RegisterConfirmation
é usado apenas para teste. A verificação automática de conta deve ser desabilitada em um aplicativo de produção.
Para exigir uma conta confirmada e impedir o logon imediato durante o registro, defina DisplayConfirmAccountLink = false
no arquivo /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
gerado por 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();
}
}
}
Essa etapa só é necessária quando Account.RegisterConfirmation
é gerado por scaffolding. O RegisterConfirmation não gerado por scaffolding detecta automaticamente quando um IEmailSender foi implementado e registrado com o contêiner de injeção de dependência.
Registrar, confirmar email e redefinir senha
Execute o aplicativo Web e teste o fluxo de confirmação e recuperação de senha da conta.
- Execute o aplicativo e registre um novo usuário
- Verifique seu email para obter o link de confirmação da conta. Consulte Depurar email se você não receber o email.
- Clique no link para confirmar seu email.
- Entre com o endereço de email e senha.
- Saia.
Testar redefinição de senha
- Se você estiver conectado, selecione Sair.
- Selecione o link Fazer logon e selecione o link Esqueceu sua senha?.
- Insira o email que você usou para registrar a conta.
- Um email com um link para redefinir sua senha é enviado. Verifique seu email e clique no link para redefinir sua senha. Depois que sua senha tiver sido redefinida com sucesso, você poderá entrar com seu email e a nova senha.
Reenviar confirmação de email
No ASP.NET Core 5.0 e posterior, selecione o link Reenviar confirmação de email na página Fazer logon.
Alterar o tempo limite de email e de atividade
O tempo limite de inatividade padrão é de 14 dias. O código a seguir define o tempo limite de inatividade como 5 dias:
services.ConfigureApplicationCookie(o => {
o.ExpireTimeSpan = TimeSpan.FromDays(5);
o.SlidingExpiration = true;
});
Alterar todos os tempos de vida do token de proteção de dados
O código a seguir altera o tempo limite de todos os tokens de proteção de dados para 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();
}
Os tokens internos de usuário Identity (consulte AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs) têm um tempo limite de um dia.
Alterar o tempo de vida do token de email
O tempo de vida do token padrão dos tokens Identity de usuário é de um dia. Esta seção mostra como alterar o tempo de vida do token de email.
Adicionar um DataProtectorTokenProvider<TUser> e 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);
}
}
Adicione o provedor personalizado ao contêiner de serviço:
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 email
Se você não conseguir usar o email:
- Defina um ponto de interrupção em
EmailSender.Execute
para verificar seSendGridClient.SendEmailAsync
é chamado. - Crie um aplicativo de console para enviar emails usando um código semelhante a
EmailSender.Execute
. - Examine a página Atividade de Email.
- Verifique sua pasta de spam.
- Experimente outro alias de email em um provedor de email diferente (Microsoft, Yahoo, Gmail etc.)
- Tente enviar para contas de email diferentes.
A melhor prática de segurança é não usar segredos de produção em ambiente de teste e de desenvolvimento. Se você publicar o aplicativo no Azure, defina os segredos do SendGrid como configurações de aplicativo no portal do Aplicativo Web do Azure. O sistema de configuração é definido para ler chaves de variáveis de ambiente.
Combinar contas de logon sociais e locais
Para concluir esta seção, primeiro você deve habilitar um provedor externo de autenticação. Consulte Autenticação do Facebook, Google e de provedor externo.
Você pode combinar contas locais e sociais clicando em seu link de email. Na sequência a seguir, “RickAndMSFT@gmail.com” é criado primeiro como um logon local. No entanto, você pode criar a conta como logon social primeiro e, em seguida, adicionar um logon local.
Clique no link Gerenciar. Observe 0 (logon social) externo associado a essa conta.
Clique no link para outro serviço de logon e aceite as solicitações do aplicativo. Na imagem a seguir, o Facebook é o provedor externo de autenticação:
As duas contas foram combinadas. Você pode fazer logon com qualquer conta. Talvez você queira que os usuários adicionem contas locais caso o serviço de autenticação de logon social esteja inativo ou provavelmente eles tenham perdido o acesso à conta social.
Habilitar a confirmação da conta depois que um site tiver usuários
Habilitar a confirmação da conta em um site com usuários bloqueia todos os usuários existentes. Os usuários existentes são bloqueados porque suas contas não foram confirmadas. Para contornar o bloqueio de usuário existente, use uma das seguintes abordagens:
- Atualize o banco de dados para marcar todos os usuários existentes como sendo confirmados.
- Confirme os usuários existentes. Por exemplo, enviar emails em lote com links de confirmação.