问题 使用2FA的Asp.Net标识 - 记住会话后不保留浏览器cookie


我正在使用最新的MVC5.2示例代码与Asp.Identity和双因素身份验证。

启用2FA后,当用户登录时,会提示输入代码(通过电话或电子邮件发送),并且他们可以选择“记住浏览器” - 这样他们就不会在该浏览器上再次询问代码。

这在VerifyCode操作中处理

var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent:  model.RememberMe, rememberBrowser: model.RememberBrowser);

注意 model.RememberMe 未在默认模板中使用,因此它为false。

我发现当我这样做的时候 .AspNet.TwoFactorRememberBrowser 设置已设置,会话结束时到期(因此不记得浏览器)

现在,如果我设置 isPersistent = true.AspNet.TwoFactorRememberBrowser 到期30天这很好,但是 .AspNet.ApplicationCookie 也会有30天到期 - 这意味着当我关闭浏览器并重新打开时,我会自动登录。

我想要它,以便它不会持续我的登录,但它将坚持我选择记住2FA代码。即用户应始终必须登录,但如果他们已经保存,则不应要求他们提供2fa代码。

有没有人看过这个,或者我错过了什么?


5949
2018-02-26 14:34


起源

你找到了解决方案吗? - karol
不,我暂时离开了,但是没有人遇到同样的问题。我打算很快再回过头来。你有同样的问题吗? - Peter Kerr
我确实得到了同样的问题:(我也测试了并且在此处找到的示例项目得到了相同的结果(asp.net/mvc/overview/security/...并为作者留下评论。如果他做出回应并提供任何见解,我将确保在此发布。 - karol
我按照上面链接的教程的作者的要求提交了一个问题。问题在这里: aspnetidentity.codeplex.com/workitem/2532   随意添加评论或其他任何内容。我也回到了这里。 - karol
它似乎默认设置了14天的到期日期 - 我在浏览器中查看了Cookie信息以确定到期日期(Chrome:设置/高级/内容设置/所有Cookie和网站数据/ - Peter Kerr


答案:


看起来这个代码似乎不是为了在同一个请求/响应中设置多个身份cookie,因为OWIN cookie处理程序最终共享相同的AuthenticationProperties。这是因为AuthenticationResponseGrant具有单个主体,但主体可以具有多个身份。

您可以通过在特定于2FA cookie提供程序的ResponseSignIn和ResponseSignedIn事件中更改然后还原AuthenticationProperties来解决此错误:

        //Don't use this.
        //app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);

        //Set the 2FA cookie expiration and persistence directly
        //ExpireTimeSpan and SlidingExpiration should match the Asp.Net Identity cookie setting
        app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            AuthenticationType = DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie,
            AuthenticationMode = AuthenticationMode.Passive,
            CookieName = DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie,
            ExpireTimeSpan = TimeSpan.FromHours(2),
            SlidingExpiration = true,
            Provider = new CookieAuthenticationProvider
            {
                OnResponseSignIn = ctx =>
                {
                    ctx.OwinContext.Set("auth-prop-expires", ctx.Properties.ExpiresUtc);
                    ctx.OwinContext.Set("auth-prop-persist", ctx.Properties.IsPersistent);
                    var issued = ctx.Properties.IssuedUtc ?? DateTimeOffset.UtcNow;
                    ctx.Properties.ExpiresUtc = issued.AddDays(14);
                    ctx.Properties.IsPersistent = true;
                },
                OnResponseSignedIn = ctx =>
                {
                    ctx.Properties.ExpiresUtc = ctx.OwinContext.Get<DateTimeOffset?>("auth-prop-expires");
                    ctx.Properties.IsPersistent = ctx.OwinContext.Get<bool>("auth-prop-persist");
                }
            }
        });

确保将相同的ExpireTimeSpan和SldingExpiration设置为主要的Asp.Net Identity cookie以保留这些设置(因为它们在AuthenticationResponseGrant中合并)。


12
2017-08-23 15:59



这似乎对我有用,至少它现在设置了cookie的到期时间。我使用的是asp.net Identity 2.2.1,我不得不使用nuget更新到Microsoft.Owin 3.0.1版并添加程序集绑定重定向,以便能够使用CookieAuthenticationProvider的OnResponseSignedIn属性。 - Joel McBeth
为了补充Barry的答案,我在Identity的代码中做了一些调查,问题似乎并不存在。它似乎是在Microsoft.Owin.Security程序集中的疏忽,在AuthenticationManager.SignIn方法中似乎试图在AuthenticationResponseGrant中使用相同的设置设置两个cookie,如Barry所说。 - AbeyMarquez


这似乎仍然是Identity 2.2.1中的一个问题(它可以在Asp.Net Identity 3.0中修复 - 但目前已经发布,需要更高版本的.Net框架4.5)

以下工作现在似乎没问题: 使用错误的值在SignInManager.TwoFactorSignInAsync上设置cookie,因此在VerifyCode操作的成功时,我将cookie重置为持久性并给它我希望的到期日期(在这种情况下我将其设置为一年)

  public async Task<ActionResult> VerifyCode(VerifyCodeViewModel model)
  {
        if (!ModelState.IsValid)
        {
            return View(model);
        }            var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent:  model.RememberMe, rememberBrowser: model.RememberBrowser);
        switch (result)
        {
            case SignInStatus.Success:
                // if we remember the browser, we need to adjsut the expiry date as persisted above
                // Also set the expiry date for the .AspNet.ApplicationCookie 
                if (model.RememberBrowser)
                {
                    var user = await UserManager.FindByIdAsync(await SignInManager.GetVerifiedUserIdAsync());
                    var rememberBrowserIdentity = AuthenticationManager.CreateTwoFactorRememberBrowserIdentity(user.Id);
                    AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddDays(365) }, rememberBrowserIdentity);
                }

                return RedirectToLocal(model.ReturnUrl);

2
2018-06-16 15:23



这也不太正确。它为AspNet.TwoFactorRememberBrowser cookie提供了年份到期日期,但它也将.AspNet.ApplicationCookie设置为具有相同的到期日期 - 我不想要它。但是,当用户随后注销并重新登录时,.AspNet.ApplicationCookie会重置回会话cookie(这就是我想要的)。 - Peter Kerr
进一步的解决方法是在验证上面的代码后再次将用户注销 - 不理想 - 但它会得到所需的结果 - Peter Kerr
另一种解决方法:如果用户正确验证了代码并选择了“记住浏览器”,请在下一个请求中手动修改TwoFactorRememberBrowser cookie到期日期。我在Application_PostAuthenticateRequest中执行此操作。这有点难看,但到目前为止对我来说效果很好。 - karol