在 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) 使用短信。说明适用于twilio和ASPSMS,但你可以使用任何其他 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 帐户,例如twilio或ASPSMS。记录身份验证凭据 (twilio: accountSid 和 authToken 的 ASPSMS: 用户密钥和密码)。
找出 SMS 提供程序凭据Figuring out SMS Provider credentials
Twilio
在 Twilio 帐户的 "仪表板" 选项卡中,复制 "帐户 SID " 和 "身份验证令牌"。
ASPSMS:
从帐户设置中,导航到用户密钥,并将其与密码一起复制。
稍后我们将这些值存储在中,密钥管理器工具 SMSAccountIdentification
和 SMSAccountPassword
中。
指定 SenderID / 原始发件人Specifying SenderID / Originator
Twilio: 从 "数字" 选项卡中,复制 Twilio 的电话号码。
ASPSMS: 在 "解锁工作项" 菜单中,解锁一个或多个发信方,或选择一个字母数字发信方(并非所有网络都支持)。
稍后我们将在密钥 SMSAccountFrom
中将此值与机密管理器工具存储在一起。
SMS 服务提供的凭据Provide credentials for the SMS service
我们将使用Options 模式来访问用户帐户和密钥设置。
- 创建一个类来提取安全 SMS 项。对于本示例,在SMSoptions文件中创建了
SMSoptions
类。
namespace Web2FA.Services
{
public class SMSoptions
{
public string SMSAccountIdentification { get; set; }
public string SMSAccountPassword { get; set; }
public string SMSAccountFrom { get; set; }
}
}
用机密管理器工具设置 SMSAccountIdentification
、SMSAccountPassword
和 SMSAccountFrom
。例如:
C:/Web2FA/src/WebApp1>dotnet user-secrets set SMSAccountIdentification 12345
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
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
namespace Web2FA.Services
{
// This class is used by the application to send Email and SMS
// when you turn on two-factor authentication in ASP.NET Identity.
// For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
public class AuthMessageSender : IEmailSender, ISmsSender
{
public AuthMessageSender(IOptions<SMSoptions> optionsAccessor)
{
Options = optionsAccessor.Value;
}
public SMSoptions Options { get; } // set only via Secret Manager
public Task SendEmailAsync(string email, string subject, string message)
{
// Plug in your email service here to send an email.
return Task.FromResult(0);
}
public Task SendSmsAsync(string number, string message)
{
// Plug in your SMS service here to send a text message.
// Your Account SID from twilio.com/console
var accountSid = Options.SMSAccountIdentification;
// Your Auth Token from twilio.com/console
var authToken = Options.SMSAccountPassword;
TwilioClient.Init(accountSid, authToken);
return MessageResource.CreateAsync(
to: new PhoneNumber(number),
from: new PhoneNumber(Options.SMSAccountFrom),
body: message);
}
}
}
ASPSMS:
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
namespace Web2FA.Services
{
// This class is used by the application to send Email and SMS
// when you turn on two-factor authentication in ASP.NET Identity.
// For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
public class AuthMessageSender : IEmailSender, ISmsSender
{
public AuthMessageSender(IOptions<SMSoptions> optionsAccessor)
{
Options = optionsAccessor.Value;
}
public SMSoptions Options { get; } // set only via Secret Manager
public Task SendEmailAsync(string email, string subject, string message)
{
// Plug in your email service here to send an email.
return Task.FromResult(0);
}
public Task SendSmsAsync(string number, string message)
{
ASPSMS.SMS SMSSender = new ASPSMS.SMS();
SMSSender.Userkey = Options.SMSAccountIdentification;
SMSSender.Password = Options.SMSAccountPassword;
SMSSender.Originator = Options.SMSAccountFrom;
SMSSender.AddRecipient(number);
SMSSender.MessageData = message;
SMSSender.SendTextSMS();
return Task.FromResult(0);
}
}
}
配置要使用的启动 SMSoptionsConfigure startup to use SMSoptions
将 SMSoptions
添加到Startup.cs中 ConfigureServices
方法中的服务容器:
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
services.Configure<SMSoptions>(Configuration);
}
启用双因素身份验证Enable two-factor authentication
打开Views/管理/索引。 cshtml Razor 视图文件并删除注释字符(因此不会注释掉标记)。
使用双因素身份验证登录Log in with two-factor authentication
- 运行应用并注册一个新用户
- 点击你的用户名,该名称将激活管理控制器中的
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 失败访问尝试后)。成功的身份验证失败的访问尝试计数重置并重置时钟。可通过MaxFailedAccessAttempts和DefaultLockoutTimeSpan设置最大失败访问尝试和锁定时间。以下 10 分钟后访问尝试失败 10 次配置帐户锁定:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
services.Configure<IdentityOptions>(options =>
{
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
});
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
services.Configure<SMSoptions>(Configuration);
}
确认PasswordSignInAsync将 lockoutOnFailure
设置为 true
:
var result = await _signInManager.PasswordSignInAsync(
Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);