Asp.Net Identity中TwoFactorRecoveryCodeSignInAsync始终调用失败求助
双因素恢复码登录失败问题排查与解决
问题描述
已成功生成双因素恢复码,数据库[dbo].[AspNetUserTokens]表中存在对应记录,但调用TwoFactorRecoveryCodeSignInAsync始终验证失败,代码持续进入错误分支。尝试将恢复码空格替换为分号(匹配数据库存储格式)、直接删除空格两种方式,均无效。
相关代码
[HttpPost] public async Task<ActionResult> LoginWithRecoveryCode(LoginwithRecoveryCodeViewModel loginwithRecoveryCodeViewModel) { if (!ModelState.IsValid) { return View(loginwithRecoveryCodeViewModel); } var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); if (user == null) { throw new InvalidOperationException($"Unable to load two-factor authentication user."); } var recoveryCode = Regex.Replace(loginwithRecoveryCodeViewModel.RecoveryCode, "\\s+", ";"); var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode); if (result.Succeeded) { return LocalRedirect(loginwithRecoveryCodeViewModel.ReturnUrl ?? Url.Content("~/")); } else { ModelState.AddModelError(string.Empty, "Invalid recovery code entered."); return View(loginwithRecoveryCodeViewModel); } }
解决方法
- 禁止手动修改恢复码为分号格式:数据库中存储的带分号的恢复码是系统哈希处理后的内部格式,和用户输入的原始恢复码不直接对应。
TwoFactorRecoveryCodeSignInAsync会自动处理原始恢复码中的空格,无需手动替换分号。 - 修正恢复码处理逻辑:移除空格替换为分号的代码,改为直接清除空格或使用原始输入:
// 清除所有空格 var recoveryCode = Regex.Replace(loginwithRecoveryCodeViewModel.RecoveryCode, "\\s+", string.Empty); // 或直接使用用户输入(系统自动兼容空格) var recoveryCode = loginwithRecoveryCodeViewModel.RecoveryCode; - 确认恢复码未被使用:每个恢复码仅能使用一次,使用后会被系统失效。测试时务必使用新生成的未使用过的恢复码。
- 验证用户上下文一致性:检查
GetTwoFactorAuthenticationUserAsync获取的用户ID,是否与数据库中恢复码关联的用户ID一致,避免会话过期或上下文丢失导致用户不匹配。 - 启用详细日志排查:在
appsettings.json中配置Identity日志级别为Debug,查看验证失败的具体原因:{ "Logging": { "LogLevel": { "Microsoft.AspNetCore.Identity": "Debug" } } }
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

