ASP.NET Core 2 Identity添加SMS多因素认证方案咨询
我刚好在ASP.NET Core 2.0 Identity里实现过SMS多因素认证,给你梳理一套贴合新版架构的实操步骤,比旧文档的示例更实用:
核心实现步骤
1. 先搭建短信发送服务
首先需要一个能发送短信的服务,你可以对接第三方短信平台(比如Twilio、阿里云短信),先写个接口和实现示例:
// 定义短信发送接口 public interface ISmsSender { Task SendSmsAsync(string phoneNumber, string message); } // 模拟实现(生产环境要替换成真实服务商调用) public class SmsSender : ISmsSender { public async Task SendSmsAsync(string phoneNumber, string message) { // 这里替换成你用的短信API调用逻辑 // 比如Twilio的:await _twilioClient.Messages.CreateAsync(...) Console.WriteLine($"发送短信到 {phoneNumber}:{message}"); await Task.CompletedTask; } }
然后在Startup.cs的ConfigureServices里注册这个服务:
services.AddTransient<ISmsSender, SmsSender>();
2. 配置Identity的SMS TokenProvider
在Identity配置里,添加手机号对应的Token生成器,让Identity能生成用于SMS验证的验证码:
services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders() // 添加手机号TokenProvider,自定义名称"Phone"后续会用到 .AddTokenProvider<PhoneNumberTokenProvider<IdentityUser>>("Phone");
3. 完善用户手机号绑定流程
用户必须先绑定手机号才能用SMS MFA,所以要在账户管理页面(比如Manage/Index)添加绑定逻辑:
- 用户输入手机号后,点击「发送验证码」:
var user = await _userManager.GetUserAsync(User); var verificationCode = await _userManager.GenerateChangePhoneNumberTokenAsync(user, inputPhoneNumber); await _smsSender.SendSmsAsync(inputPhoneNumber, $"你的手机号绑定验证码:{verificationCode}"); - 用户输入验证码后,完成绑定:
var result = await _userManager.ChangePhoneNumberAsync(user, inputPhoneNumber, inputCode); if (result.Succeeded) { await _signInManager.RefreshSignInAsync(user); // 绑定成功提示 }
4. 调整登录流程的MFA分支
在登录的Post方法里,验证密码成功后,判断用户是否启用了SMS MFA:
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true); if (result.Succeeded) { var user = await _userManager.FindByEmailAsync(Input.Email); if (await _userManager.GetTwoFactorEnabledAsync(user)) { // 获取用户可用的MFA方式 var validProviders = await _userManager.GetValidTwoFactorProvidersAsync(user); if (validProviders.Contains("Phone")) { // 生成SMS验证码并发送 var smsCode = await _userManager.GenerateTwoFactorTokenAsync(user, "Phone"); await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), $"你的登录验证码:{smsCode}"); // 跳转到验证码输入页,传递MFA类型为"Phone" return RedirectToAction(nameof(VerifyCode), new { provider = "Phone", returnUrl = returnUrl, rememberMe = Input.RememberMe }); } // 如果只有Authenticator,就跳转到对应的验证页 return RedirectToAction(nameof(VerifyCode), new { provider = "Authenticator", returnUrl = returnUrl, rememberMe = Input.RememberMe }); } // 未启用MFA,直接登录 return LocalRedirect(returnUrl); }
5. 验证码验证逻辑
在VerifyCode页面,处理SMS验证码的验证:
var result = await _signInManager.TwoFactorSignInAsync(Input.Provider, Input.Code, Input.RememberMe, rememberClient: Input.RememberMe); if (result.Succeeded) { return LocalRedirect(returnUrl); } else if (result.IsLockedOut) { return RedirectToAction(nameof(Lockout)); } else { ModelState.AddModelError(string.Empty, "无效的验证码,请重新输入"); return Page(); }
关键注意事项
- 生产环境一定要替换
SmsSender的模拟实现为正规短信服务商的API调用,避免验证码无法发送 - 可以在
Startup.cs里配置验证码有效期:services.Configure<DataProtectionTokenProviderOptions>(options => { options.TokenLifespan = TimeSpan.FromMinutes(5); // 验证码5分钟内有效 }); - 要处理用户未绑定手机号却想启用SMS MFA的情况,引导用户先完成手机号绑定
内容的提问来源于stack exchange,提问作者cgipson
相关产品推荐
相关产品推荐

