【问题标题】:RedirectToAction starts new sessionRedirectToAction 开始新会话
【发布时间】:2017-12-11 14:08:11
【问题描述】:

我有一个控制器可以登录我的用户。假设它是现有用户并且密码正确,我检查他们是否启用了 2fa。

AccountControler 登录方式

public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        if (ModelState.IsValid)
        {
            // This doesn't count login failures towards account lockout
            // To enable password failures to trigger account lockout, set lockoutOnFailure: true
            var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, _configurationSettings.LockoutOnFailure);
            if (result.Succeeded)
            {
                var user = await _userManager.FindByEmailAsync(model.Email);
                await _signInManager.SignInAsync(user, _configurationSettings.IsPersistent);
                _logger.LogInformation("User logged in.");
                return RedirectToLocal(returnUrl);
            }
            if (result.RequiresTwoFactor)
            {
                return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });
            }
            if (result.IsLockedOut)
            {
                _logger.LogWarning("User account locked out.");
                return RedirectToAction(nameof(Lockout));
            }

            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return View(model);
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

假设用户确实启用了 2fa,然后我将他们重定向到 LoginWith2fa 方法。

  [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> LoginWith2fa(bool rememberMe, string returnUrl = null)
    {
        // Ensure the user has gone through the username & password screen first
        var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();

        if (user == null)
        {
            throw new ApplicationException($"Unable to load two-factor authentication user.");
        }

        var model = new LoginWith2faViewModel { RememberMe = rememberMe };
        ViewData["ReturnUrl"] = returnUrl;

        return View(model);
    }

这是我的问题所在 var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); 总是返回 null。我放了几个断点,看起来它在 ApplicationSignInManager 和 AccountController 中重新调用了我的构造函数。在那里给我一个新的会话。

SignInManager 在 startup.cs 中注册为 scoped

services.AddIdentity<ApplicationUser, IdentityRole<long>>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddSignInManager<ApplicationSignInManager>()
            .AddDefaultTokenProviders();

如何调用 RedirectToAction 并保留同一个会话?

我一直在关注这个项目Identity Server 4 Demo

更新:关于 HttpContext 的评论

【问题讨论】:

  • 范围请求lifetime 仅适用于当前请求。通过使用RedirectToAction,您将 302 发送回浏览器,然后浏览器向您的新操作发出 new 请求,从而创建新范围。
  • UseTwoFactorSignInCookie(...); 出现在您的解决方案中吗?
  • @Mackan 我认为这对于 ASP.NET Core 来说不是必需的。
  • @serpent5 啊,核心。我太落后了。 回到身份 2
  • 纯粹为了诊断,看看在LoginWith2fa 中运行await HttpContext.AuthenticateAsync(IdentityConstants.TwoFactorUserIdScheme) 返回的值 - 那是null?这是第一个电话,本质上是GetTwoFactorAuthenticationUserAsync 中的第一个电话。

标签: c# asp.net-core .net-core identityserver4 two-factor-authentication


【解决方案1】:

感谢@muqeetkhan 给我提示。因为我使用的是自定义 SignInManager,所以它需要设置正确的会话 cookie,以便将用户数据传播到下一页。

public class ApplicationSignInManager : SignInManager<ApplicationUser>
    {

        private readonly ILogger _logger;
        public ApplicationSignInManager(UserManager<ApplicationUser> userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor,
            ILogger<ApplicationSignInManager> logger, IAuthenticationSchemeProvider schemes) : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes)
        {
            _logger = logger;
        }

        public override async Task<SignInResult> PasswordSignInAsync(string userEmail, string password, bool isPersistent, bool shouldLockout)
        {
            if (UserManager == null)
                return SignInResult.Failed;
            var result = await new FindUserCommand(_logger, UserManager, userEmail, password, shouldLockout).Execute();

            if (result != SignInResult.TwoFactorRequired) return result;

            var user = await UserManager.FindByEmailAsync(userEmail);
            return await SignInOrTwoFactorAsync(user, true);   // Required sets the session Cookie
        }
    }

基本上需要调用SignInOrTwoFactorAsync(user, true);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多