使用 Asp.Net Core Identity Core 为单页应用程序实施 2FA
Implementing 2FA with Asp.Net Core Identity Core For a Single Page Application
我正在尝试使用 Asp.Net Core Identity 为 SPA 实施 2FA。但是我卡住了。
Authenticate2fa
方法的完整代码见文末
在代码中,下面的行始终为 user
设置空值。我认为 SignInManager.PasswordSignInAsync()
中发生了一些神奇的事情,但是即使我参考了源代码,我也找不到神奇的地方。
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
因此 await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, false, false);
根本行不通。
有关于如何为 MVC 实现 2FA 的官方文档,但是我找不到任何与 SPA 相关的内容。
我走在正确的轨道上还是我错过了什么?
[HttpPost]
[Route("authenticate2fa")]
public async Task<IActionResult> Authenticate2fa([FromBody]LoginModel loginModel)
{
if (ModelState.IsValid)
{
var loginResult = await _signInManager.PasswordSignInAsync(loginModel.Username, loginModel.Password, isPersistent: false, lockoutOnFailure: false);
if (!loginResult.Succeeded && !loginResult.RequiresTwoFactor)
{
return BadRequest("user-password-error");
}
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if(user == null)
{
return BadRequest("unable-to-load-2fa-user");
}
var authenticatorCode = loginModel.TwoFactorCode.Replace(" ", string.Empty).Replace("-", string.Empty);
var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, false, false);
if (result.Succeeded)
{
return Ok(await GenerateAuthenticatedUser(user));
}
else if (result.IsLockedOut)
{
return BadRequest("account-locked");
}
else
{
return BadRequest("invalid-2fa-code");
}
}
return BadRequest(ModelState);
}
我自己解决了这个问题。
我只是直接用下面的方法来验证二元token
UserManager.VerifyTwoFactorTokenAsync(...)
由于 SignInManager 依赖于 HttpContext
,它使用 IAuthenticationService
提供商来处理 2FA 请求,您需要查看 IdentityConstants.TwoFactorUserIdScheme
的提供商是什么 IAuthenticationHandlerProvider
。在我的例子中,TwoFactorUserIdScheme
由 CookieAuthenticationHandler
处理。
虽然它是 JWT 令牌,但毫无疑问它不起作用。
有一个更简单的方法。如果您想编写自己的 two-factor 身份验证,但由于无法通过 TwoFactorAuthenticatorSignInAsync() 而陷入困境(因为它总是 returns 失败),您可以直接登录。所以在 LoginWith2fa.chhtml 中,您 1) 确认他们输入了您通过 text/email 发送给他们的 2fa 代码,2) 然后您 force-log 他们像这样:
await _signInManager.SignInAsync(user, true, null);
这只是强制他们登录。我在构建管理功能时使用了这段代码,这样我们的管理员就可以在不知道密码的情况下查看系统中的任何人。非常强大。
如果您不这样做,您将被迫覆盖 iUserValidator() 和 iClaimsTransformation() 并在 Startup 中注册内容。工作量太大,没有必要。
我正在尝试使用 Asp.Net Core Identity 为 SPA 实施 2FA。但是我卡住了。
Authenticate2fa
方法的完整代码见文末
在代码中,下面的行始终为 user
设置空值。我认为 SignInManager.PasswordSignInAsync()
中发生了一些神奇的事情,但是即使我参考了源代码,我也找不到神奇的地方。
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
因此 await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, false, false);
根本行不通。
有关于如何为 MVC 实现 2FA 的官方文档,但是我找不到任何与 SPA 相关的内容。
我走在正确的轨道上还是我错过了什么?
[HttpPost]
[Route("authenticate2fa")]
public async Task<IActionResult> Authenticate2fa([FromBody]LoginModel loginModel)
{
if (ModelState.IsValid)
{
var loginResult = await _signInManager.PasswordSignInAsync(loginModel.Username, loginModel.Password, isPersistent: false, lockoutOnFailure: false);
if (!loginResult.Succeeded && !loginResult.RequiresTwoFactor)
{
return BadRequest("user-password-error");
}
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if(user == null)
{
return BadRequest("unable-to-load-2fa-user");
}
var authenticatorCode = loginModel.TwoFactorCode.Replace(" ", string.Empty).Replace("-", string.Empty);
var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, false, false);
if (result.Succeeded)
{
return Ok(await GenerateAuthenticatedUser(user));
}
else if (result.IsLockedOut)
{
return BadRequest("account-locked");
}
else
{
return BadRequest("invalid-2fa-code");
}
}
return BadRequest(ModelState);
}
我自己解决了这个问题。
我只是直接用下面的方法来验证二元token
UserManager.VerifyTwoFactorTokenAsync(...)
由于 SignInManager 依赖于 HttpContext
,它使用 IAuthenticationService
提供商来处理 2FA 请求,您需要查看 IdentityConstants.TwoFactorUserIdScheme
的提供商是什么 IAuthenticationHandlerProvider
。在我的例子中,TwoFactorUserIdScheme
由 CookieAuthenticationHandler
处理。
虽然它是 JWT 令牌,但毫无疑问它不起作用。
有一个更简单的方法。如果您想编写自己的 two-factor 身份验证,但由于无法通过 TwoFactorAuthenticatorSignInAsync() 而陷入困境(因为它总是 returns 失败),您可以直接登录。所以在 LoginWith2fa.chhtml 中,您 1) 确认他们输入了您通过 text/email 发送给他们的 2fa 代码,2) 然后您 force-log 他们像这样:
await _signInManager.SignInAsync(user, true, null);
这只是强制他们登录。我在构建管理功能时使用了这段代码,这样我们的管理员就可以在不知道密码的情况下查看系统中的任何人。非常强大。
如果您不这样做,您将被迫覆盖 iUserValidator() 和 iClaimsTransformation() 并在 Startup 中注册内容。工作量太大,没有必要。