IDS4双因素认证场景下如何获取生成的OTP用于短信/邮件发送
问题核心澄清
首先你要搞清楚一个基本逻辑:Authenticator App类应用生成的TOTP验证码从来不是服务端提前生成、存储后下发的。你提到的SignInManager.TwoFactorAuthenticatorSignInAsync校验逻辑,和用户手机上的身份验证器App逻辑完全一致:都是拿用户绑定身份验证器时双方交换留存的共享密钥,结合当前标准时间戳,按照RFC6238规定的TOTP算法计算出6位数字,两边计算结果匹配就算校验通过,根本不存在服务端"预先生成好、可以直接读取的OTP码"。
短信/邮件OTP场景的正确实现方式
你要做短信、邮件渠道发OTP的需求,完全不需要去碰Authenticator TOTP的逻辑,ASP.NET Core Identity本身就内置了对应场景的令牌提供方,直接用内置API就能拿到可发送的OTP码,步骤如下:
- 注册Identity服务时,确保启用默认令牌提供方:
services.AddIdentity<你的用户实体类, 你的角色实体类>(options => { // 原有Authenticator相关配置可以保留,不冲突 options.Tokens.AuthenticatorTokenProvider = TokenOptions.DefaultAuthenticatorProvider; }) .AddDefaultTokenProviders(); // 必须调用该方法,注入邮件、短信场景所需的令牌生成器
- 需要发码时,调用
UserManager内置的二因素令牌生成方法,直接拿到可发送的OTP字符串:
// 生成邮件渠道用的二因素登录OTP string emailOtpCode = await _userManager.GenerateTwoFactorTokenAsync( user: 当前登录流程中的用户实体, tokenProvider: TokenOptions.DefaultEmailProvider ); // 生成短信渠道用的二因素登录OTP string smsOtpCode = await _userManager.GenerateTwoFactorTokenAsync( user: 当前登录流程中的用户实体, tokenProvider: TokenOptions.DefaultPhoneProvider );
拿到上述code变量的值之后,直接对接你的短信、邮件发送接口下发给用户即可。
- 用户提交收到的验证码后,不要调用
TwoFactorAuthenticatorSignInAsync做校验——这个方法是专门给Authenticator App的TOTP校验用的,你需要调用通用二因素校验方法:
var signInResult = await _signInManager.TwoFactorSignInAsync( provider: TokenOptions.DefaultEmailProvider, // 发码用的哪个提供方这里就传哪个,短信场景传DefaultPhoneProvider code: 用户提交的验证码, isPersistent: 是否保留长期登录Cookie, rememberClient: 是否记住当前设备,下次登录跳过二因素 );
后续你就可以按照signInResult的返回状态判断校验是否成功,走后续登录流程即可。
特别提醒:不建议你尝试自行计算和Authenticator App完全一致的TOTP码用于短信/邮件发送。要实现这个逻辑你需要在服务端持久化存储用户Authenticator的明文共享密钥,一旦数据库泄露,所有用户的身份验证器二因素防护会直接失效,安全风险极高;同时自行实现TOTP算法还要处理时间窗口偏移、时钟不同步等问题,很容易出现用户填了正确验证码却校验失败的情况,完全没必要。
内容的提问来源于stack exchange,提问作者Mehdi Payervand
相关产品推荐
相关产品推荐

