帐户确认和 ASP.NET Core 中的密码恢复Account confirmation and password recovery in ASP.NET Core

本文内容

作者: Rick AndersonPonantJoe Audette

本教程介绍如何使用电子邮件确认和密码重置构建 ASP.NET Core 应用。本教程是开始主题。您应熟悉:

有关 ASP.NET Core 1.1 版本,请参阅此 PDF 文件

先决条件Prerequisites

.NET Core 3.0 SDK 或更高版本

创建和测试使用身份验证的 web 应用Create and test a web app with authentication

运行以下命令,创建具有身份验证的 web 应用。

  1. dotnet new webapp -au Individual -uld -o WebPWrecover
  2. cd WebPWrecover
  3. dotnet run

运行应用,选择 "注册" 链接,然后注册用户。注册后,会重定向到 /Identity/Account/RegisterConfirmation "页面,其中包含用于模拟电子邮件确认的链接:

  • 选择 "Click here to confirm your account" 链接。
  • 选择 "登录" 链接,并以相同的凭据登录。
  • 选择 "Hello YourEmail@provider.com!" 链接,该链接会将你重定向到 /Identity/Account/Manage/PersonalData 页面。
  • 选择左侧的 "个人数据" 选项卡,然后选择 "删除"。

配置电子邮件提供程序Configure an email provider

在本教程中,使用SendGrid发送电子邮件。需要使用 SendGrid 帐户和密钥来发送电子邮件。您可以使用其他电子邮件提供程序。建议使用 SendGrid 或其他电子邮件服务发送电子邮件。SMTP 难于保护和正确设置。

创建一个类以获取安全电子邮件密钥。对于本示例,请创建服务/AuthMessageSenderOptions

  1. public class AuthMessageSenderOptions
  2. {
  3. public string SendGridUser { get; set; }
  4. public string SendGridKey { get; set; }
  5. }

配置 SendGrid 用户机密Configure SendGrid user secrets

机密管理器工具设置 SendGridUserSendGridKey例如:

  1. dotnet user-secrets set SendGridUser RickAndMSFT
  2. dotnet user-secrets set SendGridKey <key>
  3. Successfully saved SendGridUser = RickAndMSFT to the secret store.

在 Windows 上,机密管理器将密钥/值对存储在 %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> 目录中的 Secret 文件中

不会对机密 json文件的内容进行加密。以下标记显示了机密的 json文件。已删除 SendGridKey 值。

  1. {
  2. "SendGridUser": "RickAndMSFT",
  3. "SendGridKey": "<key removed>"
  4. }

有关详细信息,请参阅Options 模式配置

安装 SendGridInstall SendGrid

本教程介绍如何通过SendGrid添加电子邮件通知,但你可以使用 SMTP 和其他机制发送电子邮件。

安装 SendGrid NuGet 包:

在 "包管理器控制台" 中,输入以下命令:

  1. Install-Package SendGrid

在控制台中,输入以下命令:

  1. dotnet add package SendGrid

请参阅SendGrid 的入门免费版,注册免费 SendGrid 帐户。

实现 IEmailSenderImplement IEmailSender

若要实现 IEmailSender,请创建具有类似于下面的代码的服务 EmailSender

  1. using Microsoft.AspNetCore.Identity.UI.Services;
  2. using Microsoft.Extensions.Options;
  3. using SendGrid;
  4. using SendGrid.Helpers.Mail;
  5. using System.Threading.Tasks;
  6. namespace WebPWrecover.Services
  7. {
  8. public class EmailSender : IEmailSender
  9. {
  10. public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor)
  11. {
  12. Options = optionsAccessor.Value;
  13. }
  14. public AuthMessageSenderOptions Options { get; } //set only via Secret Manager
  15. public Task SendEmailAsync(string email, string subject, string message)
  16. {
  17. return Execute(Options.SendGridKey, subject, message, email);
  18. }
  19. public Task Execute(string apiKey, string subject, string message, string email)
  20. {
  21. var client = new SendGridClient(apiKey);
  22. var msg = new SendGridMessage()
  23. {
  24. From = new EmailAddress("Joe@contoso.com", Options.SendGridUser),
  25. Subject = subject,
  26. PlainTextContent = message,
  27. HtmlContent = message
  28. };
  29. msg.AddTo(new EmailAddress(email));
  30. // Disable click tracking.
  31. // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
  32. msg.SetClickTracking(false, false);
  33. return client.SendEmailAsync(msg);
  34. }
  35. }
  36. }

配置启动以支持电子邮件Configure startup to support email

将以下代码添加到Startup.cs文件的 ConfigureServices 方法中:

  • EmailSender 添加为暂时性服务。
  • 注册 AuthMessageSenderOptions 配置实例。
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDbContext<ApplicationDbContext>(options =>
  4. options.UseSqlServer(
  5. Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddDefaultIdentity<IdentityUser>(
  7. options => options.SignIn.RequireConfirmedAccount = true)
  8. .AddEntityFrameworkStores<ApplicationDbContext>();
  9. // requires
  10. // using Microsoft.AspNetCore.Identity.UI.Services;
  11. // using WebPWrecover.Services;
  12. services.AddTransient<IEmailSender, EmailSender>();
  13. services.Configure<AuthMessageSenderOptions>(Configuration);
  14. services.AddRazorPages();
  15. }

注册、确认电子邮件并重置密码Register, confirm email, and reset password

运行 web 应用,并测试帐户确认和密码恢复流。

  • 运行应用并注册一个新用户
  • 检查电子邮件中的 "帐户确认" 链接。如果没有收到电子邮件,请参阅调试电子邮件
  • 单击链接以确认你的电子邮件。
  • 用电子邮件和密码登录。
  • 注销。

测试密码重置Test password reset

  • 如果已登录,请选择 "注销"。
  • 选择 "登录" 链接,然后选择 "忘记了密码?" 链接。
  • 输入用于注册该帐户的电子邮件。
  • 发送了一封电子邮件,其中包含用于重置密码的链接。检查你的电子邮件,然后单击链接以重置你的密码。密码重置成功后,可以用电子邮件和新密码登录。

更改电子邮件和活动超时Change email and activity timeout

默认的非活动超时为14天。下面的代码将非活动超时设置为5天:

  1. services.ConfigureApplicationCookie(o => {
  2. o.ExpireTimeSpan = TimeSpan.FromDays(5);
  3. o.SlidingExpiration = true;
  4. });

更改所有数据保护令牌 lifespansChange all data protection token lifespans

以下代码将所有数据保护令牌超时期限更改为3小时:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDbContext<ApplicationDbContext>(options =>
  4. options.UseSqlServer(
  5. Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddDefaultIdentity<IdentityUser>(
  7. options => options.SignIn.RequireConfirmedAccount = true)
  8. .AddEntityFrameworkStores<ApplicationDbContext>();
  9. services.Configure<DataProtectionTokenProviderOptions>(o =>
  10. o.TokenLifespan = TimeSpan.FromHours(3));
  11. services.AddTransient<IEmailSender, EmailSender>();
  12. services.Configure<AuthMessageSenderOptions>(Configuration);
  13. services.AddRazorPages();
  14. }

内置标识用户令牌(请参阅AspNetCore/src/Identity/extension/src/src/TokenOptions )具有一天的超时时间

更改电子邮件令牌的生命周期Change the email token lifespan

标识用户令牌的默认令牌生存期为1 天本部分介绍如何更改电子邮件令牌的生命周期。

添加自定义的DataProtectorTokenProvider<TUser >DataProtectionTokenProviderOptions

  1. public class CustomEmailConfirmationTokenProvider<TUser>
  2. : DataProtectorTokenProvider<TUser> where TUser : class
  3. {
  4. public CustomEmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
  5. IOptions<EmailConfirmationTokenProviderOptions> options,
  6. ILogger<DataProtectorTokenProvider<TUser>> logger)
  7. : base(dataProtectionProvider, options, logger)
  8. {
  9. }
  10. }
  11. public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
  12. {
  13. public EmailConfirmationTokenProviderOptions()
  14. {
  15. Name = "EmailDataProtectorTokenProvider";
  16. TokenLifespan = TimeSpan.FromHours(4);
  17. }
  18. }

将自定义提供程序添加到服务容器:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDbContext<ApplicationDbContext>(options =>
  4. options.UseSqlServer(
  5. Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddDefaultIdentity<IdentityUser>(config =>
  7. {
  8. config.SignIn.RequireConfirmedEmail = true;
  9. config.Tokens.ProviderMap.Add("CustomEmailConfirmation",
  10. new TokenProviderDescriptor(
  11. typeof(CustomEmailConfirmationTokenProvider<IdentityUser>)));
  12. config.Tokens.EmailConfirmationTokenProvider = "CustomEmailConfirmation";
  13. }).AddEntityFrameworkStores<ApplicationDbContext>();
  14. services.AddTransient<CustomEmailConfirmationTokenProvider<IdentityUser>>();
  15. services.AddTransient<IEmailSender, EmailSender>();
  16. services.Configure<AuthMessageSenderOptions>(Configuration);
  17. services.AddRazorPages();
  18. }

重新发送电子邮件确认Resend email confirmation

请参阅此 GitHub 问题

调试电子邮件Debug email

如果无法使用电子邮件:

  • EmailSender.Execute 中设置断点以验证是否调用了 SendGridClient.SendEmailAsync
  • 创建一个控制台应用程序,以便使用类似的代码将电子邮件发送到 EmailSender.Execute
  • 查看电子邮件活动页。
  • 检查垃圾邮件文件夹。
  • 尝试使用其他电子邮件提供商(Microsoft、Yahoo、Gmail 等)中的另一个电子邮件别名
  • 尝试发送到不同的电子邮件帐户。

最佳安全做法在测试和开发中使用生产机密。如果将应用发布到 Azure,请在 Azure Web 应用门户中将 "SendGrid 机密" 设置为 "应用程序设置"。配置系统设置以从环境变量读取密钥。

合并社会和本地登录帐户Combine social and local login accounts

若要完成本部分,必须首先启用外部身份验证提供程序。请参阅Facebook、Google 和外部提供程序身份验证

可以通过单击电子邮件链接来合并本地帐户和社交帐户。按照以下顺序,"RickAndMSFT@gmail.com" 首先创建为本地登录名;但是,你可以先将帐户创建为社交登录名,然后添加本地登录名。

Web 应用程序: RickAndMSFT@gmail.com 用户已进行身份验证

单击 "管理" 链接。请注意与此帐户关联的0个外部(社交登录)。

管理视图

单击指向另一登录服务的链接,并接受应用请求。在下图中,Facebook 是外部身份验证提供程序:

管理你的外部登录名视图列表 Facebook

这两个帐户已组合在一起。你可以用任一帐户登录。你可能希望用户在社交登录身份验证服务关闭时添加本地帐户,或者更可能的情况是他们失去了社交帐户的访问权限。

在站点包含用户后启用帐户确认Enable account confirmation after a site has users

在具有用户的站点上启用帐户确认会锁定所有现有用户。现有用户被锁定,因为其帐户未得到确认。若要解决现有用户锁定,请使用以下方法之一:

  • 更新数据库,将所有现有用户标记为已确认。
  • 确认现有用户。例如,批处理-发送包含确认链接的电子邮件。

先决条件Prerequisites

.NET Core 2.2 SDK 或更高版本

创建 web 应用和基架标识Create a web app and scaffold Identity

运行以下命令,创建具有身份验证的 web 应用。

  1. dotnet new webapp -au Individual -uld -o WebPWrecover
  2. cd WebPWrecover
  3. dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
  4. dotnet tool install -g dotnet-aspnet-codegenerator
  5. dotnet aspnet-codegenerator identity -dc WebPWrecover.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.Logout;Account.ConfirmEmail"
  6. dotnet ef database drop -f
  7. dotnet ef database update
  8. dotnet run

测试新用户注册Test new user registration

运行应用,选择 "注册" 链接,然后注册用户。此时,该电子邮件的唯一验证是带有[EmailAddress]特性。提交注册后,将登录到应用。在本教程的后面部分,将更新代码,以便新用户在验证其电子邮件之前无法登录。

查看标识数据库View the Identity database

  • 从 "视图" 菜单中选择 " SQL Server 对象资源管理器" (SSOX)。
  • 导航到 (localdb) MSSQLLocalDB (SQL Server 13) 。右键单击 " dbo"。AspNetUsers > 查看数据

SQL Server 对象资源管理器中的 AspNetUsers 表上的上下文菜单

您可以下载许多第三方工具来管理和查看 SQLite 数据库,例如DB Browser For sqlite

请注意,表的 EmailConfirmed 字段是 False的。

当应用发送确认电子邮件时,可能需要在下一步中再次使用此电子邮件。右键单击该行,然后选择 "删除"。删除电子邮件别名可以简化以下步骤。

需要确认电子邮件Require email confirmation

最佳做法是确认新用户注册的电子邮件。电子邮件确认有助于验证他们是否未模拟其他人(即,他们未注册其他人的电子邮件)。假设你有讨论论坛,并且想要阻止 "yli@example.com" 注册为 "nolivetto@contoso.com"。如果未确认电子邮件,"nolivetto@contoso.com" 可能会从你的应用收到不需要的电子邮件。假设用户意外注册为 "ylo@example.com",未注意到 "yli" 的拼写错误。它们不能使用密码恢复,因为该应用没有正确的电子邮件。电子邮件确认为 bot 提供有限的保护。电子邮件确认不会为具有多个电子邮件帐户的恶意用户提供保护。

通常,在用户确认电子邮件之前,会阻止新用户将任何数据发布到您的网站。

更新 Startup.ConfigureServices,要求确认电子邮件:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDbContext<ApplicationDbContext>(options =>
  4. options.UseSqlServer(
  5. Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddDefaultIdentity<IdentityUser>(config =>
  7. {
  8. config.SignIn.RequireConfirmedEmail = true;
  9. })
  10. .AddDefaultUI(UIFramework.Bootstrap4)
  11. .AddEntityFrameworkStores<ApplicationDbContext>();
  12. // requires
  13. // using Microsoft.AspNetCore.Identity.UI.Services;
  14. // using WebPWrecover.Services;
  15. services.AddTransient<IEmailSender, EmailSender>();
  16. services.Configure<AuthMessageSenderOptions>(Configuration);
  17. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  18. }

config.SignIn.RequireConfirmedEmail = true; 阻止注册的用户登录,直到其电子邮件得到确认。

配置电子邮件提供程序Configure email provider

在本教程中,使用SendGrid发送电子邮件。需要使用 SendGrid 帐户和密钥来发送电子邮件。您可以使用其他电子邮件提供程序。ASP.NET Core 2.x 包括 System.Net.Mail,这允许你从应用发送电子邮件。建议使用 SendGrid 或其他电子邮件服务发送电子邮件。SMTP 难于保护和正确设置。

创建一个类以获取安全电子邮件密钥。对于本示例,请创建服务/AuthMessageSenderOptions

  1. public class AuthMessageSenderOptions
  2. {
  3. public string SendGridUser { get; set; }
  4. public string SendGridKey { get; set; }
  5. }

配置 SendGrid 用户机密Configure SendGrid user secrets

机密管理器工具设置 SendGridUserSendGridKey例如:

  1. C:/WebAppl>dotnet user-secrets set SendGridUser RickAndMSFT
  2. info: Successfully saved SendGridUser = RickAndMSFT to the secret store.

在 Windows 上,机密管理器将密钥/值对存储在 %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> 目录中的 Secret 文件中

不会对机密 json文件的内容进行加密。以下标记显示了机密的 json文件。已删除 SendGridKey 值。

  1. {
  2. "SendGridUser": "RickAndMSFT",
  3. "SendGridKey": "<key removed>"
  4. }

有关详细信息,请参阅Options 模式配置

安装 SendGridInstall SendGrid

本教程介绍如何通过SendGrid添加电子邮件通知,但你可以使用 SMTP 和其他机制发送电子邮件。

安装 SendGrid NuGet 包:

在 "包管理器控制台" 中,输入以下命令:

  1. Install-Package SendGrid

在控制台中,输入以下命令:

  1. dotnet add package SendGrid

请参阅SendGrid 的入门免费版,注册免费 SendGrid 帐户。

实现 IEmailSenderImplement IEmailSender

若要实现 IEmailSender,请创建具有类似于下面的代码的服务 EmailSender

  1. using Microsoft.AspNetCore.Identity.UI.Services;
  2. using Microsoft.Extensions.Options;
  3. using SendGrid;
  4. using SendGrid.Helpers.Mail;
  5. using System.Threading.Tasks;
  6. namespace WebPWrecover.Services
  7. {
  8. public class EmailSender : IEmailSender
  9. {
  10. public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor)
  11. {
  12. Options = optionsAccessor.Value;
  13. }
  14. public AuthMessageSenderOptions Options { get; } //set only via Secret Manager
  15. public Task SendEmailAsync(string email, string subject, string message)
  16. {
  17. return Execute(Options.SendGridKey, subject, message, email);
  18. }
  19. public Task Execute(string apiKey, string subject, string message, string email)
  20. {
  21. var client = new SendGridClient(apiKey);
  22. var msg = new SendGridMessage()
  23. {
  24. From = new EmailAddress("Joe@contoso.com", "Joe Smith"),
  25. Subject = subject,
  26. PlainTextContent = message,
  27. HtmlContent = message
  28. };
  29. msg.AddTo(new EmailAddress(email));
  30. // Disable click tracking.
  31. // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
  32. msg.SetClickTracking(false, false);
  33. return client.SendEmailAsync(msg);
  34. }
  35. }
  36. }

配置启动以支持电子邮件Configure startup to support email

将以下代码添加到Startup.cs文件的 ConfigureServices 方法中:

  • EmailSender 添加为暂时性服务。
  • 注册 AuthMessageSenderOptions 配置实例。
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDbContext<ApplicationDbContext>(options =>
  4. options.UseSqlServer(
  5. Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddDefaultIdentity<IdentityUser>(config =>
  7. {
  8. config.SignIn.RequireConfirmedEmail = true;
  9. })
  10. .AddDefaultUI(UIFramework.Bootstrap4)
  11. .AddEntityFrameworkStores<ApplicationDbContext>();
  12. // requires
  13. // using Microsoft.AspNetCore.Identity.UI.Services;
  14. // using WebPWrecover.Services;
  15. services.AddTransient<IEmailSender, EmailSender>();
  16. services.Configure<AuthMessageSenderOptions>(Configuration);
  17. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  18. }

启用帐户确认和密码恢复Enable account confirmation and password recovery

该模板包含用于帐户确认和密码恢复的代码。区域/标识/页面/帐户/注册. .cs中查找 OnPostAsync 方法。

通过注释掉以下行,阻止新注册的用户自动登录:

  1. await _signInManager.SignInAsync(user, isPersistent: false);

将显示完整的方法,其中突出显示了已更改的行:

  1. public async Task<IActionResult> OnPostAsync(string returnUrl = null)
  2. {
  3. returnUrl = returnUrl ?? Url.Content("~/");
  4. if (ModelState.IsValid)
  5. {
  6. var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
  7. var result = await _userManager.CreateAsync(user, Input.Password);
  8. if (result.Succeeded)
  9. {
  10. _logger.LogInformation("User created a new account with password.");
  11. var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
  12. var callbackUrl = Url.Page(
  13. "/Account/ConfirmEmail",
  14. pageHandler: null,
  15. values: new { userId = user.Id, code = code },
  16. protocol: Request.Scheme);
  17. await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
  18. $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
  19. //await _signInManager.SignInAsync(user, isPersistent: false);
  20. return LocalRedirect(returnUrl);
  21. }
  22. foreach (var error in result.Errors)
  23. {
  24. ModelState.AddModelError(string.Empty, error.Description);
  25. }
  26. }
  27. // If we got this far, something failed, redisplay form
  28. return Page();
  29. }

注册、确认电子邮件并重置密码Register, confirm email, and reset password

运行 web 应用,并测试帐户确认和密码恢复流。

  • 运行应用并注册一个新用户
  • 检查电子邮件中的 "帐户确认" 链接。如果没有收到电子邮件,请参阅调试电子邮件
  • 单击链接以确认你的电子邮件。
  • 用电子邮件和密码登录。
  • 注销。

查看 "管理" 页View the manage page

在浏览器中选择你的用户名,并在浏览器中选择用户名](accconfirm/_static/un.png) ![浏览器窗口

将显示 "管理" 页,并选中 "配置文件" 选项卡。电子邮件将显示一个复选框,指示已确认电子邮件。

测试密码重置Test password reset

  • 如果已登录,请选择 "注销"。
  • 选择 "登录" 链接,然后选择 "忘记了密码?" 链接。
  • 输入用于注册该帐户的电子邮件。
  • 发送了一封电子邮件,其中包含用于重置密码的链接。检查你的电子邮件,然后单击链接以重置你的密码。密码重置成功后,可以用电子邮件和新密码登录。

更改电子邮件和活动超时Change email and activity timeout

默认的非活动超时为14天。下面的代码将非活动超时设置为5天:

  1. services.ConfigureApplicationCookie(o => {
  2. o.ExpireTimeSpan = TimeSpan.FromDays(5);
  3. o.SlidingExpiration = true;
  4. });

更改所有数据保护令牌 lifespansChange all data protection token lifespans

以下代码将所有数据保护令牌超时期限更改为3小时:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDbContext<ApplicationDbContext>(options =>
  4. options.UseSqlServer(
  5. Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddDefaultIdentity<IdentityUser>(config =>
  7. {
  8. config.SignIn.RequireConfirmedEmail = true;
  9. })
  10. .AddDefaultUI(UIFramework.Bootstrap4)
  11. .AddEntityFrameworkStores<ApplicationDbContext>();
  12. services.Configure<DataProtectionTokenProviderOptions>(o =>
  13. o.TokenLifespan = TimeSpan.FromHours(3));
  14. services.AddTransient<IEmailSender, EmailSender>();
  15. services.Configure<AuthMessageSenderOptions>(Configuration);
  16. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  17. }

内置标识用户令牌(请参阅AspNetCore/src/Identity/extension/src/src/TokenOptions )具有一天的超时时间

更改电子邮件令牌的生命周期Change the email token lifespan

标识用户令牌的默认令牌生存期为1 天本部分介绍如何更改电子邮件令牌的生命周期。

添加自定义的DataProtectorTokenProvider<TUser >DataProtectionTokenProviderOptions

  1. public class CustomEmailConfirmationTokenProvider<TUser>
  2. : DataProtectorTokenProvider<TUser> where TUser : class
  3. {
  4. public CustomEmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
  5. IOptions<EmailConfirmationTokenProviderOptions> options)
  6. : base(dataProtectionProvider, options)
  7. {
  8. }
  9. }
  10. public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
  11. {
  12. public EmailConfirmationTokenProviderOptions()
  13. {
  14. Name = "EmailDataProtectorTokenProvider";
  15. TokenLifespan = TimeSpan.FromHours(4);
  16. }
  17. }

将自定义提供程序添加到服务容器:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDbContext<ApplicationDbContext>(options =>
  4. options.UseSqlServer(
  5. Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddDefaultIdentity<IdentityUser>(config =>
  7. {
  8. config.SignIn.RequireConfirmedEmail = true;
  9. config.Tokens.ProviderMap.Add("CustomEmailConfirmation",
  10. new TokenProviderDescriptor(
  11. typeof(CustomEmailConfirmationTokenProvider<IdentityUser>)));
  12. config.Tokens.EmailConfirmationTokenProvider = "CustomEmailConfirmation";
  13. })
  14. .AddDefaultUI(UIFramework.Bootstrap4)
  15. .AddEntityFrameworkStores<ApplicationDbContext>();
  16. services.AddTransient<CustomEmailConfirmationTokenProvider<IdentityUser>>();
  17. services.AddTransient<IEmailSender, EmailSender>();
  18. services.Configure<AuthMessageSenderOptions>(Configuration); // For SendGrid key.
  19. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  20. }

重新发送电子邮件确认Resend email confirmation

请参阅此 GitHub 问题

调试电子邮件Debug email

如果无法使用电子邮件:

  • EmailSender.Execute 中设置断点以验证是否调用了 SendGridClient.SendEmailAsync
  • 创建一个控制台应用程序,以便使用类似的代码将电子邮件发送到 EmailSender.Execute
  • 查看电子邮件活动页。
  • 检查垃圾邮件文件夹。
  • 尝试使用其他电子邮件提供商(Microsoft、Yahoo、Gmail 等)中的另一个电子邮件别名
  • 尝试发送到不同的电子邮件帐户。

最佳安全做法在测试和开发中使用生产机密。如果将应用发布到 Azure,则可以在 Azure Web 应用门户中将 SendGrid 机密设置为应用程序设置。配置系统设置以从环境变量读取密钥。

合并社会和本地登录帐户Combine social and local login accounts

若要完成本部分,必须首先启用外部身份验证提供程序。请参阅Facebook、Google 和外部提供程序身份验证

可以通过单击电子邮件链接来合并本地帐户和社交帐户。按照以下顺序,"RickAndMSFT@gmail.com" 首先创建为本地登录名;但是,你可以先将帐户创建为社交登录名,然后添加本地登录名。

Web 应用程序: RickAndMSFT@gmail.com 用户已进行身份验证

单击 "管理" 链接。请注意与此帐户关联的0个外部(社交登录)。

管理视图

单击指向另一登录服务的链接,并接受应用请求。在下图中,Facebook 是外部身份验证提供程序:

管理你的外部登录名视图列表 Facebook

这两个帐户已组合在一起。你可以用任一帐户登录。你可能希望用户在社交登录身份验证服务关闭时添加本地帐户,或者更可能的情况是他们失去了社交帐户的访问权限。

在站点包含用户后启用帐户确认Enable account confirmation after a site has users

在具有用户的站点上启用帐户确认会锁定所有现有用户。现有用户被锁定,因为其帐户未得到确认。若要解决现有用户锁定,请使用以下方法之一:

  • 更新数据库,将所有现有用户标记为已确认。
  • 确认现有用户。例如,批处理-发送包含确认链接的电子邮件。