英文:
SignInManager always fails for TwoFactorAuthenticatorSignInAsync() and TwoFactorSignInAsync()
问题
背景
我正在使用.NET 6构建一个API,在其中尝试实现使用Google Authenticator的双因素身份验证。一切都运行正常,直到我尝试使用认证器应用程序提供的代码进行登录的最后步骤。
代码
双因素身份验证设置 - 第一部分:
[HttpGet("TwoFactorAuthSetup/{email}")]
public async Task<IActionResult> GetTwoFactorAuthSetup(string email)
{
...
var isTwoFactorAuthEnabled = await _userManager.GetTwoFactorEnabledAsync(user);
var authenticatorKey = await _userManager.GetAuthenticatorKeyAsync(user);
if (authenticatorKey == null)
{
await _userManager.ResetAuthenticatorKeyAsync(user);
authenticatorKey = await _userManager.GetAuthenticatorKeyAsync(user);
}
...
}
双因素身份验证设置 - 第二部分:
[HttpPost("TwoFactorAuthSetup")]
public async Task<IActionResult> SetupTwoFactorAuth([FromBody] TwoFactorAuthSetupDto model)
{
var user = await _userManager.FindByEmailAsync(model.Email);
var isCodeValid = await _userManager
.VerifyTwoFactorTokenAsync(user,
_userManager.Options.Tokens.AuthenticatorTokenProvider,
model.Code);
if (!isCodeValid)
{
return BadRequest("Invalid code");
}
await _userManager.SetTwoFactorEnabledAsync(user, true);
...
}
双因素身份验证登录:
[HttpPost("login-2fa")]
[AllowAnonymous]
public async Task<IActionResult> LoginWithTwoFactorAuth(TwoFactorAuthSetupDto model)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
return Unauthorized();
}
var result = await _signInManager.TwoFactorSignInAsync(_userManager.Options.Tokens.AuthenticatorTokenProvider, model.Code, true, false);
var result2 = await _signInManager.TwoFactorAuthenticatorSignInAsync(model.Code, true, false);
}
双因素身份验证设置的第一部分和第二部分按预期运行;我能够在我的应用程序中成功设置authenticatorKey,并且控制器能够接受6位代码。
问题出现在尝试使用认证器应用程序登录时。无论是result
还是result2
最终都为Succeeded = false。当我尝试使用_userManager.VerifyTwoFactorTokenAsync
方法时,它确实显示我使用的代码是有效的。我不确定该如何继续。
英文:
Background
I'm building an API with .NET 6 where I'm currently trying to implement two factor authentication using Google Authenticator. It seems to be working fine up until the final part where I actually try to sign in using the code provided by the authenticator app.
Code
2FA Setup - Part 1:
[HttpGet("TwoFactorAuthSetup/{email}")]
public async Task<IActionResult> GetTwoFactorAuthSetup(string email)
{
...
var isTwoFactorAuthEnabled = await _userManager.GetTwoFactorEnabledAsync(user);
var authenticatorKey = await _userManager.GetAuthenticatorKeyAsync(user);
//var authenticatorKey = await _userManager.GenerateNewAuthenticatorKey(user);
if (authenticatorKey == null)
{
await _userManager.ResetAuthenticatorKeyAsync(user);
authenticatorKey = await _userManager.GetAuthenticatorKeyAsync(user);
}
...
2FA Setup - Part 2:
[HttpPost("TwoFactorAuthSetup")]
public async Task<IActionResult> SetupTwoFactorAuth([FromBody] TwoFactorAuthSetupDto model)
{
var user = await _userManager.FindByEmailAsync(model.Email);
var isCodeValid = await _userManager
.VerifyTwoFactorTokenAsync(user,
_userManager.Options.Tokens.AuthenticatorTokenProvider,
model.Code);
if (!isCodeValid)
{
return BadRequest("Invalid code");
}
await _userManager.SetTwoFactorEnabledAsync(user, true);
...
2FA Login:
[HttpPost("login-2fa")]
[AllowAnonymous]
public async Task<IActionResult> LoginWithTwoFactorAuth(TwoFactorAuthSetupDto model)
{
var user = await _userManager.FindByEmailAsync(model.Email);
//user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
return Unauthorized();
}
//var isValid = await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, model.Code);
var result = await _signInManager.TwoFactorSignInAsync(_userManager.Options.Tokens.AuthenticatorTokenProvider, model.Code, true, false);
var result2 = await _signInManager.TwoFactorAuthenticatorSignInAsync( model.Code, true, false);
Both 2FA Setup - Part 1 and 2FA Setup - Part 2 work as expected; I'm able to successfully setup the authenticatorKey in my app, and the 6-digit code gets accepted by my controller.
The issue arises when trying to sign in using the authenticator app. Both result and result2 always end up with Succeeded = false. When I try to use the _userManager.VerifyTwoFactorTokenAsync
method instead, it does show me that the code I use is valid. I'm unsure of how to proceed.
答案1
得分: 1
我弄清楚了。如果你有类似的问题,请考虑以下两个步骤:
-
使用
_signInManager.PasswordSignInAsync
登录用户。这会生成一个 cookie,以便在用户选择记住我时记住用户。 -
使用
var user = _signInManager.GetTwoFactorAuthenticationUserAsync()
来检查Identity.TwoFactorUserId
cookie 的存在。
我之前犯了一些错误:
- 我使用了
_signInManager.CheckPasswordSignInAsync
而不是_signInManager.PasswordSignInAsync
。 - 我错误地使用了
var user = await _userManager.FindByEmailAsync(model.Email);
来获取需要执行两因素身份验证登录的用户。这存在安全风险。我后来用await _signInManager.GetTwoFactorAuthenticationUserAsync()
替换了这一行。
通过上述更改,现在它按预期工作。
英文:
I figured it out. In case you have a similar issue, consider the following two steps -
-
Use
_signInManager.PasswordSignInAsync
to sign in the user. This drops a cookie that helps remember the user in case they had ticked the remember me. -
Use
var user = _signInManager.GetTwoFactorAuthenticationuserAsync()
which checks for the presence of theIdentity.TwoFactorUserId
cookie.
I made few mistakes earlier:
- I used
_signInManager.CheckPasswordSignInAsync
instead of_signInManager.PasswordSignInAsync
. - I mistakenly used
var user = await _userManager.FindByEmailAsync(model.Email);
to get the user for which 2 factor auth login had to be performed. This provides a security risk. I since replaced this line withawait _signInManager.GetTwoFactorAuthenticationUserAsync()
.
With the changes mentioned above it now works as intended.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论