Confirmação de conta e de recuperação de senha no ASP.NET Core Blazor
Este artigo explica como configurar um aplicativo Web do ASP.NET Core Blazor com confirmação de email e recuperação de senha.
Namespace
O namespace do aplicativo usado pelo exemplo neste artigo é BlazorSample
. Atualize os exemplos de código para usar o namespace do seu aplicativo.
Selecionar e configurar um provedor de email
Neste artigo, a API Transacional do Mailchimp é usada via Mandrill.net para enviar emails. É recomendável usar um serviço de email para enviar email em vez de SMTP. SMTP é difícil de configurar e proteger corretamente. Seja qual for o serviço de email usado, acesse suas orientações para aplicativos .NET, crie uma conta, configure uma chave de API para seu serviço e instale os pacotes NuGet necessários.
Crie uma classe para buscar a chave de API de email segura. O exemplo neste artigo usa uma classe nomeada AuthMessageSenderOptions
com uma propriedade EmailAuthKey
para manter a chave.
AuthMessageSenderOptions
:
namespace BlazorSample;
public class AuthMessageSenderOptions
{
public string? EmailAuthKey { get; set; }
}
Registre a instância de configuração AuthMessageSenderOptions
no arquivo Program
:
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
Configurar um segredo do usuário para a chave de segurança do provedor
Defina a chave com a ferramenta secret-manager. No exemplo a seguir, o nome da chave é EmailAuthKey
e a chave é representada pelo espaço reservado {KEY}
. Em um shell de comando, navegue até a pasta raiz do aplicativo e execute o seguinte comando com a chave de API:
dotnet user-secrets set "EmailAuthKey" "{KEY}"
Para obter mais informações, confira Armazenamento seguro de segredos do aplicativo em desenvolvimento no ASP.NET Core.
Implementa IEmailSender
Implementar IEmailSender
para o provedor. O exemplo a seguir é baseado na API Transacional do Mailchimp usando Mandrill.net. Para um provedor diferente, consulte sua documentação sobre como implementar o envio de uma mensagem no método Execute
.
Components/Account/EmailSender.cs
:
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Mandrill;
using Mandrill.Model;
using BlazorSample.Data;
namespace BlazorSample.Components.Account;
public class EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
ILogger<EmailSender> logger) : IEmailSender<ApplicationUser>
{
private readonly ILogger logger = logger;
public AuthMessageSenderOptions Options { get; } = optionsAccessor.Value;
public Task SendConfirmationLinkAsync(ApplicationUser user, string email,
string confirmationLink) => SendEmailAsync(email, "Confirm your email",
"Please confirm your account by " +
$"<a href='{confirmationLink}'>clicking here</a>.");
public Task SendPasswordResetLinkAsync(ApplicationUser user, string email,
string resetLink) => SendEmailAsync(email, "Reset your password",
$"Please reset your password by <a href='{resetLink}'>clicking here</a>.");
public Task SendPasswordResetCodeAsync(ApplicationUser user, string email,
string resetCode) => SendEmailAsync(email, "Reset your password",
$"Please reset your password using the following code: {resetCode}");
public async Task SendEmailAsync(string toEmail, string subject, string message)
{
if (string.IsNullOrEmpty(Options.EmailAuthKey))
{
throw new Exception("Null EmailAuthKey");
}
await Execute(Options.EmailAuthKey, subject, message, toEmail);
}
public async Task Execute(string apiKey, string subject, string message,
string toEmail)
{
var api = new MandrillApi(apiKey);
var mandrillMessage = new MandrillMessage("sarah@contoso.com", toEmail,
subject, message);
await api.Messages.SendAsync(mandrillMessage);
logger.LogInformation("Email to {EmailAddress} sent!", toEmail);
}
}
Observação
O conteúdo do corpo das mensagens pode exigir codificação especial para o provedor de serviços de email. Se os links no corpo da mensagem não puderem ser seguidos, confira a documentação do provedor de serviços.
Configurar o aplicativo para dar suporte ao email
No arquivo Program
, altere a implementação do remetente de email para EmailSender
:
- builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
+ builder.Services.AddSingleton<IEmailSender<ApplicationUser>, EmailSender>();
Remova o IdentityNoOpEmailSender
(Components/Account/IdentityNoOpEmailSender.cs
) do aplicativo.
No componente RegisterConfirmation
(Components/Account/Pages/RegisterConfirmation.razor
), remova o bloco condicional no bloco @code
que verifica se o EmailSender
é um IdentityNoOpEmailSender
:
- else if (EmailSender is IdentityNoOpEmailSender)
- {
- ...
- }
Também no componente RegisterConfirmation
, remova a marcação Razor e o código para verificar o campo emailConfirmationLink
, deixando apenas a linha instruindo o usuário a verificar seu email...
- @if (emailConfirmationLink is not null)
- {
- ...
- }
- else
- {
<p>Please check your email to confirm your account.</p>
- }
@code {
- private string? emailConfirmationLink;
...
}
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 com expiração variável (sliding expiration):
builder.Services.ConfigureApplicationCookie(options => {
options.ExpireTimeSpan = TimeSpan.FromDays(5);
options.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:
builder.Services.Configure<DataProtectionTokenProviderOptions>(options =>
options.TokenLifespan = TimeSpan.FromHours(3));
Os tokens internos de usuário Identity (AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs) têm um tempo limite de um dia.
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).
Alterar o tempo de vida do token de email
O tempo de vida do token padrão dos tokens de usuárioIdentity é de um dia.
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).
Para alterar a vida útil do token de email, adicione um personalizado DataProtectorTokenProvider<TUser> e DataProtectionTokenProviderOptions:
CustomTokenProvider.cs
:
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
namespace BlazorSample;
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);
}
}
public class CustomPasswordResetTokenProvider<TUser>
: DataProtectorTokenProvider<TUser> where TUser : class
{
public CustomPasswordResetTokenProvider(
IDataProtectionProvider dataProtectionProvider,
IOptions<PasswordResetTokenProviderOptions> options,
ILogger<DataProtectorTokenProvider<TUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
public class PasswordResetTokenProviderOptions :
DataProtectionTokenProviderOptions
{
public PasswordResetTokenProviderOptions()
{
Name = "PasswordResetDataProtectorTokenProvider";
TokenLifespan = TimeSpan.FromHours(3);
}
}
Configure os serviços para usar o provedor de token personalizado no arquivo Program
:
builder.Services.AddIdentityCore<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Tokens.ProviderMap.Add("CustomEmailConfirmation",
new TokenProviderDescriptor(
typeof(CustomEmailConfirmationTokenProvider<ApplicationUser>)));
options.Tokens.EmailConfirmationTokenProvider =
"CustomEmailConfirmation";
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();
builder.Services
.AddTransient<CustomEmailConfirmationTokenProvider<ApplicationUser>>();
Solucionar problemas
Se você não conseguir usar o email:
- Defina um ponto de interrupção em
EmailSender.Execute
para verificar seSendEmailAsync
é chamado. - Crie um aplicativo de console para enviar emails usando código semelhante a
EmailSender.Execute
para depurar o problema. - Revise as páginas do histórico de email da conta no site do provedor de email.
- Verifique se há mensagens na pasta de spam.
- Experimente outro alias de email em um provedor de email diferente, como Microsoft, Yahoo ou Gmail.
- Tente enviar para contas de email diferentes.
Aviso
Não use segredos de produção em teste e desenvolvimento. Se você publicar o aplicativo no Azure, defina os segredos 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.
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 confirmados.
- Confirme os usuários existentes. Por exemplo, enviar emails em lote com links de confirmação.
Recursos adicionais
Comentários
https://aka.ms/ContentUserFeedback.
Brevemente: Ao longo de 2024, vamos descontinuar progressivamente o GitHub Issues como mecanismo de feedback para conteúdos e substituí-lo por um novo sistema de feedback. Para obter mais informações, veja:Submeter e ver comentários