新用户首次登录 .NET Core 时强制进行 2 因素身份验证

Force 2 Factor Authentication for new users when they login for the first time .NET Core

我正在尝试在用户首次登录 .net core 时配置 2FA。所以我添加了一个 if 条件来检查 2FA 是否未启用然后重定向到创建 MFA,但是,这里的一个主要缺陷是用户可以更改浏览器上的 URL link 以跳过 2FA 创建,我怎样才能避免这种情况?以下是我的帐户控制器代码:

登录控制器方法

[HttpGet]
        [AllowAnonymous]
        public IActionResult Login(string? returnurl = null)
        {
            ViewData["ReturnUrl"] = returnurl;
            return View();
        }

        [HttpPost]
        [AllowAnonymous]
        public async Task<IActionResult> Login(LoginViewModel model, string? returnurl = null)
        {
            ViewData["ReturnUrl"] = returnurl;
            returnurl ??= Url.Content("~/");
            if (ModelState.IsValid)
            {
                var user = await _userManager.FindByNameAsync(model.UserName);
                var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: true);
                if (result.Succeeded)
                {
                    if (user.TwoFactorEnabled==false)
                    {
                        return RedirectToAction(nameof(EnableAuthenticator), new { returnurl, model.RememberMe });
                    }
                    return LocalRedirect(returnurl);
                }

                if (result.RequiresTwoFactor)
                {
                    return RedirectToAction(nameof(VerifyAuthenticatorCode), new { returnurl, model.RememberMe });
                }
                if (result.IsLockedOut)
                {
                    return View("Lockout");
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                    return View(model);
                }
            }
            return View(model);
        }

启用 2FA 控制器方法

    [HttpGet]
    public async Task<IActionResult> EnableAuthenticator()
    {
        string AuthenticatorUriFormat = "MY-OTP-SECRET-HERE";

        var user = await _userManager.GetUserAsync(User);
        await _userManager.ResetAuthenticatorKeyAsync(user);
        var token = await _userManager.GetAuthenticatorKeyAsync(user);
        string AuthenticatorUri = string.Format(AuthenticatorUriFormat, _urlEncoder.Encode("My-App-Name-Here"),
            _urlEncoder.Encode(user.Email), token);
        var model = new MFAViewModel() { Token = token, QRCodeUrl = AuthenticatorUri };
        return View(model);
    }

    [HttpPost]
    public async Task<IActionResult> EnableAuthenticator(MFAViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = await _userManager.GetUserAsync(User);
            var succeeded = await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, model.Code);
            if (succeeded)
            {
                await _userManager.SetTwoFactorEnabledAsync(user, true);
            }
            else
            {
                ModelState.AddModelError("Verify", "Your two factor auth code could not be validated.");
                return View(model);
            }

        }
        return RedirectToAction(nameof(AuthenticatorConfirmation));
    }

如我的评论所述,您可以考虑配置应用程序使用 Claims-based authorization,在用户使用 2FA 成功登录后,您可以添加一个声明存储 2FA 登录结果并将其添加到登录用户。之后,在您的应用程序中,创建一个需要声明的策略,并在每个控制器上添加 Authorize 属性。

此外,您还可以在 2FA 之后添加用户声明,然后创建自定义 middleware/Authorize 属性来验证每个请求并检查当前用户是否包含声明。您可以参考以下链接:Custom Authorization attributes and How To Override Attribute Class To Do Custom Authorization In .NET Core.