RedirectToAction 启动新会话 [英] RedirectToAction starts new session
问题描述
我有一个登录我的用户的控制器.假设它是现有用户并且密码正确,我检查他们是否启用了 2fa.
AccountControler 登录方法
public async Task登录(LoginViewModel 模型,字符串 returnUrl = null){ViewData["ReturnUrl"] = returnUrl;如果(模型状态.IsValid){//这不计入帐户锁定的登录失败//要启用密码失败触发帐户锁定,请设置 lockoutOnFailure: truevar 结果 = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, _configurationSettings.LockoutOnFailure);如果(结果.成功){var user = await _userManager.FindByEmailAsync(model.Email);等待 _signInManager.SignInAsync(用户,_configurationSettings.IsPersistent);_logger.LogInformation("用户登录.");返回重定向到本地(returnUrl);}如果(结果.RequiresTwoFactor){return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });}如果(结果.IsLockedOut){_logger.LogWarning("用户账户被锁定.");返回 RedirectToAction(nameof(Lockout));}ModelState.AddModelError(string.Empty, "无效的登录尝试.");返回视图(模型);}//如果我们到了这一步,有些事情失败了,重新显示表单返回视图(模型);}
假设用户确实启用了 2fa,那么我将他们重定向到 LoginWith2fa 方法.
[HttpGet][允许匿名]公共异步任务LoginWith2fa(bool rememberMe, string returnUrl = null){//确保用户已经通过了用户名 &首先是密码屏幕var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();如果(用户==空){throw new ApplicationException($"无法加载双因素身份验证用户.");}var model = new LoginWith2faViewModel { RememberMe = rememberMe };ViewData["ReturnUrl"] = returnUrl;返回视图(模型);}
这是我的问题出现的地方 var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
总是返回 null.我放了几个断点,看起来它在 ApplicationSignInManager 和 AccountController 中重新调整了我的构造函数.通过给我一个新的会话.
SignInManager 在 startup.cs 中注册为作用域
services.AddIdentity>().AddEntityFrameworkStores().AddSignInManager().AddDefaultTokenProviders();
如何调用 RedirectToAction 并保持相同的会话?
我一直在关注这个项目
感谢@muqeetkhan 给我的提示.因为我使用的是自定义 SignInManager,所以它需要设置正确的会话 cookie,以便将用户数据传播到下一页.
公共类 ApplicationSignInManager : SignInManager{私有只读 ILogger _logger;public ApplicationSignInManager(UserManager userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory claimFactory, IOptions optionsAccessor,ILoggerlogger, IAuthenticationSchemeProvider 方案):base(userManager,contextAccessor,claimFactory,optionsAccessor,logger,scheme){_logger = 记录器;}公共覆盖异步任务PasswordSignInAsync(string userEmail, string password, bool isPersistent, bool shouldLockout){如果(用户管理器 == 空)返回 SignInResult.Failed;var result = await new FindUserCommand(_logger, UserManager, userEmail, password, shouldLockout).Execute();if (result != SignInResult.TwoFactorRequired) 返回结果;var user = await UserManager.FindByEmailAsync(userEmail);return await 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屋!