RedirectToAction开始新的会话 [英] RedirectToAction starts new session

查看:53
本文介绍了RedirectToAction开始新的会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

AccountControler登录方法

 公共异步任务< IActionResult>Login(LoginViewModel模型,字符串returnUrl = null){ViewData ["ReturnUrl"] = returnUrl;如果(ModelState.IsValid){//这不将登录失败计入帐户锁定//要启用密码失败来触发帐户锁定,请设置lockoutOnFailure:truevar result = await _signInManager.PasswordSignInAsync(model.Email,model.Password,model.RememberMe,_configurationSettings.LockoutOnFailure);如果(成功){var user =等待_userManager.FindByEmailAsync(model.Email);等待_signInManager.SignInAsync(user,_configurationSettings.IsPersistent);_logger.LogInformation(用户已登录.");返回RedirectToLocal(returnUrl);}如果(result.RequiresTwoFactor){return RedirectToAction(nameof(LoginWith2fa),new {returnUrl,model.RememberMe});}如果(result.IsLockedOut){_logger.LogWarning(用户帐户已锁定.");返回RedirectToAction(nameof(Lockout));}ModelState.AddModelError(string.Empty,无效的登录尝试.");返回View(model);}//如果到此为止,则出现故障,请重新显示表单返回View(model);} 

假设用户确实启用了2fa,那么我将其重定向到LoginWith2fa方法.

  [HttpGet][AllowAnonymous]公共异步Task< IActionResult>LoginWith2fa(bool RememberMe,字符串returnUrl = null){//确保用户已通过用户名&密码屏幕首先var user =等待_signInManager.GetTwoFactorAuthenticationUserAsync();如果(用户==空){抛出新的ApplicationException($无法加载两因素身份验证用户.");}var model = new LoginWith2faViewModel {RememberMe = RememberMe};ViewData ["ReturnUrl"] = returnUrl;返回View(model);} 

这是我的问题出在哪里var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); 始终返回null.我输入了一些断点,看起来它在ApplicationSignInManager和AccountController中都调整了我的构造函数.通过给我一个新的会话.

SignInManager已在startup.cs中注册为作用域

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

您如何调用RedirectToAction并保留相同的会话?

我一直在关注这个项目

解决方案

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

 公共类ApplicationSignInManager:SignInManager< ApplicationUser>{私有只读ILogger _logger;公共ApplicationSignInManager(UserManager< ApplicationUser> userManager,IHttpContextAccessor contextAccessor,IUserClaimsPrincipalFactory< ApplicationUser> ClaimsFactory,IOptions< IdentityOptions> optionsAccessor,ILogger< ApplicationSignInManager>记录器,IAuthenticationSchemeProvider方案):基础(userManager,contextAccessor,claimsFactory,optionsAccessor,记录器,方案){_logger =记录器;}公共重写异步Task< SignInResult>PasswordSignInAsync(字符串userEmail,字符串密码,bool isPersistent,bool shouldLockout){如果(UserManager == null)返回SignInResult.Failed;var result =等待新的FindUserCommand(_logger,UserManager,userEmail,password,shouldLockout).Execute();if(结果!= SignInResult.TwoFactorRequired)返回结果;var user =等待UserManager.FindByEmailAsync(userEmail);返回等待SignInOrTwoFactorAsync(user,true);//需要设置会话Cookie}} 

基本上是 SignInOrTwoFactorAsync(user,true); .

I have a controller which logins in my user. Assuming its an existing user and the password is correct i check if they have 2fa enabled.

AccountControler login method

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);
    }

Assuming the user does have 2fa enabled then i redirect them to the LoginWith2fa method.

  [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);
    }

This is where my problem comes in var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); always returns null. I put a few break points in and it looks like its recaling my constructers both in ApplicationSignInManager and the AccountController. There by giving me a new session.

SignInManager is registered as scoped in startup.cs

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

How do you call RedirectToAction and retain the same session?

I have been following this project Identity Server 4 Demo

Update: Comment about HttpContext

解决方案

Thanks to @muqeetkhan for giving me the hint. Becouse i am using a custom SignInManager it needs to set the proper session cookies in order for the user data to be propagated to the next page.

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
        }
    }

Basically SignInOrTwoFactorAsync(user, true); needs to be called.

这篇关于RedirectToAction开始新的会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆