在 ASP.NET Core SMS 的双因素身份验证Two-factor authentication with SMS in ASP.NET Core

本文内容

作者: Rick Anderson瑞士-开发人员

警告

两个身份验证 (2FA) 身份验证器应用程序,使用基于时间的一次性密码算法 (TOTP),是推荐的方法用于 2FA 的行业。2FA 使用 TOTP 优于 SMS 2FA。有关详细信息,请参阅为 ASP.NET Core 2.0 及更高版本ASP.NET Core 中的 TOTP 验证器应用启用 QR 码生成

本教程演示如何设置双因素身份验证 (2FA) 使用短信。说明适用于twilioASPSMS,但你可以使用任何其他 SMS 提供程序。建议你在开始学习本教程之前完成帐户确认和密码恢复

查看或下载示例代码如何下载

创建新的 ASP.NET Core 项目Create a new ASP.NET Core project

使用单个用户帐户创建名为 Web2FA 的新 ASP.NET Core web 应用。按照 强制实施 HTTPS 在 ASP.NET Core 中的说明设置和需要 HTTPS。

创建 SMS 帐户Create an SMS account

创建一个 SMS 帐户,例如twilioASPSMS记录身份验证凭据 (twilio: accountSid 和 authToken 的 ASPSMS: 用户密钥和密码)。

找出 SMS 提供程序凭据Figuring out SMS Provider credentials

Twilio

在 Twilio 帐户的 "仪表板" 选项卡中,复制 "帐户 SID " 和 "身份验证令牌"。

ASPSMS:

从帐户设置中,导航到用户密钥,并将其与密码一起复制。

稍后我们将这些值存储在中,密钥管理器工具 SMSAccountIdentificationSMSAccountPassword中。

指定 SenderID / 原始发件人Specifying SenderID / Originator

Twilio: 从 "数字" 选项卡中,复制 Twilio 的电话号码

ASPSMS: 在 "解锁工作项" 菜单中,解锁一个或多个发信方,或选择一个字母数字发信方(并非所有网络都支持)。

稍后我们将在密钥 SMSAccountFrom中将此值与机密管理器工具存储在一起。

SMS 服务提供的凭据Provide credentials for the SMS service

我们将使用Options 模式来访问用户帐户和密钥设置。

  • 创建一个类来提取安全 SMS 项。对于本示例,在SMSoptions文件中创建了 SMSoptions 类。
  1. namespace Web2FA.Services
  2. {
  3. public class SMSoptions
  4. {
  5. public string SMSAccountIdentification { get; set; }
  6. public string SMSAccountPassword { get; set; }
  7. public string SMSAccountFrom { get; set; }
  8. }
  9. }

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

  1. C:/Web2FA/src/WebApp1>dotnet user-secrets set SMSAccountIdentification 12345
  2. info: Successfully saved SMSAccountIdentification = 12345 to the secret store.
  • SMS 提供程序添加 NuGet 包。从包管理器控制台 (PMC) 运行:

Twilio

Install-Package Twilio

ASPSMS:

Install-Package ASPSMS

  • 添加服务/MessageServices文件中的代码以启用 SMS。使用 Twilio 或 ASPSMS 部分:

Twilio

  1. using Microsoft.Extensions.Options;
  2. using System.Threading.Tasks;
  3. using Twilio;
  4. using Twilio.Rest.Api.V2010.Account;
  5. using Twilio.Types;
  6. namespace Web2FA.Services
  7. {
  8. // This class is used by the application to send Email and SMS
  9. // when you turn on two-factor authentication in ASP.NET Identity.
  10. // For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
  11. public class AuthMessageSender : IEmailSender, ISmsSender
  12. {
  13. public AuthMessageSender(IOptions<SMSoptions> optionsAccessor)
  14. {
  15. Options = optionsAccessor.Value;
  16. }
  17. public SMSoptions Options { get; } // set only via Secret Manager
  18. public Task SendEmailAsync(string email, string subject, string message)
  19. {
  20. // Plug in your email service here to send an email.
  21. return Task.FromResult(0);
  22. }
  23. public Task SendSmsAsync(string number, string message)
  24. {
  25. // Plug in your SMS service here to send a text message.
  26. // Your Account SID from twilio.com/console
  27. var accountSid = Options.SMSAccountIdentification;
  28. // Your Auth Token from twilio.com/console
  29. var authToken = Options.SMSAccountPassword;
  30. TwilioClient.Init(accountSid, authToken);
  31. return MessageResource.CreateAsync(
  32. to: new PhoneNumber(number),
  33. from: new PhoneNumber(Options.SMSAccountFrom),
  34. body: message);
  35. }
  36. }
  37. }

ASPSMS:

  1. using Microsoft.Extensions.Options;
  2. using System.Threading.Tasks;
  3. namespace Web2FA.Services
  4. {
  5. // This class is used by the application to send Email and SMS
  6. // when you turn on two-factor authentication in ASP.NET Identity.
  7. // For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
  8. public class AuthMessageSender : IEmailSender, ISmsSender
  9. {
  10. public AuthMessageSender(IOptions<SMSoptions> optionsAccessor)
  11. {
  12. Options = optionsAccessor.Value;
  13. }
  14. public SMSoptions Options { get; } // set only via Secret Manager
  15. public Task SendEmailAsync(string email, string subject, string message)
  16. {
  17. // Plug in your email service here to send an email.
  18. return Task.FromResult(0);
  19. }
  20. public Task SendSmsAsync(string number, string message)
  21. {
  22. ASPSMS.SMS SMSSender = new ASPSMS.SMS();
  23. SMSSender.Userkey = Options.SMSAccountIdentification;
  24. SMSSender.Password = Options.SMSAccountPassword;
  25. SMSSender.Originator = Options.SMSAccountFrom;
  26. SMSSender.AddRecipient(number);
  27. SMSSender.MessageData = message;
  28. SMSSender.SendTextSMS();
  29. return Task.FromResult(0);
  30. }
  31. }
  32. }

配置要使用的启动 SMSoptionsConfigure startup to use SMSoptions

SMSoptions 添加到Startup.csConfigureServices 方法中的服务容器:

  1. // Add application services.
  2. services.AddTransient<IEmailSender, AuthMessageSender>();
  3. services.AddTransient<ISmsSender, AuthMessageSender>();
  4. services.Configure<SMSoptions>(Configuration);
  5. }

启用双因素身份验证Enable two-factor authentication

打开Views/管理/索引。 cshtml Razor 视图文件并删除注释字符(因此不会注释掉标记)。

使用双因素身份验证登录Log in with two-factor authentication

  • 运行应用并注册一个新用户

Web 应用程序注册 Microsoft Edge 中打开视图

  • 点击你的用户名,该名称将激活管理控制器中的 Index 操作方法。然后点击 "电话号码" "添加" 链接。

管理视图-点击"添加"链接

  • 添加将接收验证码的电话号码,然后点击 "发送验证码"。

添加电话号码页

  • 则会使用验证码的短信。输入它,然后点击 "提交"

验证电话号码页

如果没有收到短信,请参阅 twilio 日志页。

  • 管理视图显示已成功添加你的电话号码。

管理视图-已成功添加电话号码

  • 点击 "启用" 以启用双因素身份验证。

管理视图: 启用双因素身份验证

测试双因素身份验证Test two-factor authentication

  • 注销。

  • 登录。

  • 用户帐户已启用双因素身份验证,因此你必须提供身份验证的第二个因素。在本教程中已启用电话验证。内置的模板还可以设置电子邮件作为第二个因素。您可以设置其他身份验证的 QR 代码如第二个因素。点击 "提交"。

发送验证代码视图

  • 输入你将获得的 SMS 消息中的代码。

  • 单击 "记住此浏览器" 复选框会使你不需要使用2FA 在使用同一设备和浏览器时进行登录。如果启用2FA 并单击 "记住",此浏览器将为你提供强大的2FA 防护,防止恶意用户尝试访问你的帐户,只要他们无权访问你的设备。可以在您经常使用任何专用设备上执行此操作。通过设置记住此浏览器,你可以从不经常使用的设备中获得2FA 的增强的安全性,并且你无需在自己的设备上通过2FA。

验证视图

用于防范暴力破解攻击的帐户锁定Account lockout for protecting against brute force attacks

帐户锁定,建议使用 2FA。用户登录后通过本地帐户或社交帐户,存储在 2FA 每次失败的尝试。如果达到最大的失败的访问尝试,则用户锁定 (默认值: 5 分钟锁定 5 失败访问尝试后)。成功的身份验证失败的访问尝试计数重置并重置时钟。可通过MaxFailedAccessAttemptsDefaultLockoutTimeSpan设置最大失败访问尝试和锁定时间。以下 10 分钟后访问尝试失败 10 次配置帐户锁定:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. // Add framework services.
  4. services.AddDbContext<ApplicationDbContext>(options =>
  5. options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddIdentity<ApplicationUser, IdentityRole>()
  7. .AddEntityFrameworkStores<ApplicationDbContext>()
  8. .AddDefaultTokenProviders();
  9. services.AddMvc();
  10. services.Configure<IdentityOptions>(options =>
  11. {
  12. options.Lockout.MaxFailedAccessAttempts = 10;
  13. options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
  14. });
  15. // Add application services.
  16. services.AddTransient<IEmailSender, AuthMessageSender>();
  17. services.AddTransient<ISmsSender, AuthMessageSender>();
  18. services.Configure<SMSoptions>(Configuration);
  19. }

确认PasswordSignInAsynclockoutOnFailure 设置为 true

  1. var result = await _signInManager.PasswordSignInAsync(
  2. Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);