在ASP.NET Core中启用并使用双因素认证
我想在一个ASP.NET Core项目中使用2FA。可以通过扫描QR码(图片“Activate 2FA”)在Google身份验证器中进行激活,然后我输入六位验证码就能工作。之后我从.NET Core应用程序中注销。
但当我尝试登录时,应用显示验证码不正确(图片“Invalid authenticator code”)。不过我确实从Google Authenticator应用中获取了验证码,我的手机和电脑的时间也自动设置为相同。
你有想法吗?谢谢
代码在 EnableAuthenticator.cshmtl.cs:
using System;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using produit_chimiques.Areas.Identity.Data; // ← IMPORTANT : ton namespace ApplicationUser
namespace produit_chimiques.Areas.Identity.Pages.Account.Manage
{
[Authorize]
public class EnableAuthenticatorModel : PageModel
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly UrlEncoder _urlEncoder;
private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
public EnableAuthenticatorModel(
UserManager<ApplicationUser> userManager,
UrlEncoder urlEncoder)
{
_userManager = userManager;
_urlEncoder = urlEncoder;
}
[BindProperty]
public InputModel Input { get; set; } = new InputModel();
public string SharedKey { get; set; } = "";
public string AuthenticatorUri { get; set; } = "";
public class InputModel
{
public string Code { get; set; } = "";
}
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Impossible de charger l'utilisateur avec l'ID '{_userManager.GetUserId(User)}'.");
}
await LoadSharedKeyAndQrCodeUriAsync(user);
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Impossible de charger l'utilisateur avec l'ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadSharedKeyAndQrCodeUriAsync(user);
return Page();
}
// Nettoyer le code saisi
var verificationCode = Input.Code.Replace(" ", string.Empty)
.Replace("-", string.Empty);
/////////////////////////////////////////////////////////////////////////////////////////
// Juste AVANT VerifyTwoFactorTokenAsync, ajoute :
var debugKey = await _userManager.GetAuthenticatorKeyAsync(user);
Console.WriteLine($"DEBUG: Verification pour user {user.Id}, clé actuelle: {debugKey}");
Console.WriteLine($"DEBUG: Code saisi: {verificationCode}");
// Vérifier le code TOTP avec le provider Identity
var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync(
user,
_userManager.Options.Tokens.AuthenticatorTokenProvider,
verificationCode);
if (!is2faTokenValid)
{
ModelState.AddModelError("Input.Code", "Code non valide. Vérifiez votre application d'authentification.");
await LoadSharedKeyAndQrCodeUriAsync(user);
return Page();
}
// Activer la 2FA pour cet utilisateur
await _userManager.SetTwoFactorEnabledAsync(user, true);
await _userManager.ResetAuthenticatorKeyAsync(user);
return RedirectToPage("./TwoFactorAuthentication");
}
private async Task LoadSharedKeyAndQrCodeUriAsync(ApplicationUser user)
{
// Générer/récupérer la clé TOTP
var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
if (string.IsNullOrEmpty(unformattedKey))
{
await _userManager.ResetAuthenticatorKeyAsync(user);
unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
}
SharedKey = FormatKey(unformattedKey);
var email = await _userManager.GetEmailAsync(user) ??
await _userManager.GetUserNameAsync(user);
AuthenticatorUri = GenerateQrCodeUri(email, unformattedKey);
}
private string GenerateQrCodeUri(string email, string unformattedKey)
{
var issuer = "ProduitsChimiques";
return string.Format(
AuthenticatorUriFormat,
_urlEncoder.Encode(issuer),
_urlEncoder.Encode(email),
unformattedKey);
}
private string FormatKey(string unformattedKey)
{
const int groupSize = 4;
var result = new StringBuilder();
var currentPosition = 0;
while (currentPosition + groupSize < unformattedKey.Length)
{
result.Append(unformattedKey.AsSpan(currentPosition, groupSize));
result.Append(' ');
currentPosition += groupSize;
}
if (currentPosition < unformattedKey.Length)
{
result.Append(unformattedKey.AsSpan(currentPosition));
}
return result.ToString().ToLowerInvariant();
}
}
}
解决方案
在你的 OnPostAsync() 上,成功验证验证码后,你会调用 await _userManager.ResetAuthenticatorKeyAsync(user);,这会重置你用户的认证密钥,这意味着之前由你的用户扫描并验证过的QR码现在所使用的认证密钥与存储的不同。
因此,即使用户成功启用其2FA,你也改变了它的认证密钥,现在他的身份验证器代码就不对了。
总之,只需从你的 OnPostAsync() 中删除这一行,应该是这样的:
...
await _userManager.SetTwoFactorEnabledAsync(user, true);
//Removed await _userManager.ResetAuthenticatorKeyAsync(user);
return RedirectToPage("./TwoFactorAuthentication");
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。