asp.net-mvc - ASP 身份登录 isPersistent 不起作用

标签 asp.net-mvc cookies asp.net-identity

我正在使用 ASP Identity 进行身份验证。 Statup.Auth.cs 的一部分如下所示:

            app.UseCookieAuthentication(
            new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
                LoginPath = new PathString("/Account/Login"), 
                Provider = new CookieAuthenticationProvider
                           {
                               // Enables the application to validate the security stamp when the user logs in.
                               // This is a security feature which is used when you change a password or add an external login to your account.  
                               OnValidateIdentity =
                                   SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                                       validateInterval: TimeSpan.FromMinutes(30),
                                       regenerateIdentity:
                                   (manager, user) =>
                                   user.GenerateUserIdentityAsync(manager))
                           },
                ExpireTimeSpan = TimeSpan.FromMinutes(Settings.Default.SessionExpireTimeoutInMinutes), 
            });

以及我的登录方法的一部分:

SignInStatus result = await this.SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);

如果用户选择“记住我”选项,则在 30 天之内他不会被注销。如果他不选择此选项,他应该会在一小段时间(比如说 10 分钟)后自动注销。此时,无论用户是否选择该选项,他都会注销。

最佳答案

SecurityStampValidator 类中存在一个已知错误,该错误会阻止在重置身份验证 cookie 时保留 isPercient 属性。

问题是supposedly resolved因此您应该尝试更新所有软件包,但有些人仍然遇到问题。

解决此问题的一种方法是编写您自己的 SecurityStampValidator 类。您可以找到 Microsoft source code here 的版本.

这是我尝试过的一些似乎有效的代码(我添加了 AuthenticationProperties 并设置了 AllowRefreshIsPersistent 属性):

using Microsoft.Owin.Security.Cookies;
using Owin;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin.Security;

namespace Microsoft.AspNet.Identity.Owin
{
    /// <summary>
    /// Static helper class used to configure a CookieAuthenticationProvider to validate a cookie against a user's security stamp
    /// </summary>
    public static class MySecurityStampValidator
    {
        /// <summary>
        /// Can be used as the ValidateIdentity method for a CookieAuthenticationProvider which will check a user's security stamp after validateInterval
        /// Rejects the identity if the stamp changes, and otherwise will call regenerateIdentity to sign in a new ClaimsIdentity
        /// </summary>
        /// <typeparam name="TManager"></typeparam>
        /// <typeparam name="TUser"></typeparam>
        /// <param name="validateInterval"></param>
        /// <param name="regenerateIdentity"></param>
        /// <returns></returns>
        public static Func<CookieValidateIdentityContext, Task> OnValidateIdentity<TManager, TUser>(TimeSpan validateInterval, Func<TManager, TUser, Task<ClaimsIdentity>> regenerateIdentity)
            where TManager : UserManager<TUser, string>
            where TUser : class, IUser<string>
        {
            return OnValidateIdentity<TManager, TUser, string>(validateInterval, regenerateIdentity, (id) => id.GetUserId());
        }

        /// <summary>
        /// Can be used as the ValidateIdentity method for a CookieAuthenticationProvider which will check a user's security stamp after validateInterval
        /// Rejects the identity if the stamp changes, and otherwise will call regenerateIdentity to sign in a new ClaimsIdentity
        /// </summary>
        /// <typeparam name="TManager"></typeparam>
        /// <typeparam name="TUser"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="validateInterval"></param>
        /// <param name="regenerateIdentityCallback"></param>
        /// <param name="getUserIdCallback"></param>
        /// <returns></returns>
        public static Func<CookieValidateIdentityContext, Task> OnValidateIdentity<TManager, TUser, TKey>(TimeSpan validateInterval, Func<TManager, TUser, Task<ClaimsIdentity>> regenerateIdentityCallback, Func<ClaimsIdentity, TKey> getUserIdCallback)
            where TManager : UserManager<TUser, TKey>
            where TUser :class, IUser<TKey>
            where TKey : IEquatable<TKey>
        {
            return async (context) =>
            {
                DateTimeOffset currentUtc = DateTimeOffset.UtcNow;
                if (context.Options != null && context.Options.SystemClock != null)
                {
                    currentUtc = context.Options.SystemClock.UtcNow;
                }
                DateTimeOffset? issuedUtc = context.Properties.IssuedUtc;

                // Only validate if enough time has elapsed
                bool validate = (issuedUtc == null);
                if (issuedUtc != null)
                {
                    TimeSpan timeElapsed = currentUtc.Subtract(issuedUtc.Value);
                    validate = timeElapsed > validateInterval;
                }
                if (validate)
                {
                    var manager = context.OwinContext.GetUserManager<TManager>();
                    var userId = getUserIdCallback(context.Identity);
                    if (manager != null && userId != null)
                    {
                        var user = await manager.FindByIdAsync(userId).ConfigureAwait(false);
                        bool reject = true;
                        // Refresh the identity if the stamp matches, otherwise reject
                        if (user != null && manager.SupportsUserSecurityStamp)
                        {
                            string securityStamp = context.Identity.FindFirstValue(Constants.DefaultSecurityStampClaimType);
                            if (securityStamp == await manager.GetSecurityStampAsync(userId).ConfigureAwait(false))
                            {
                                reject = false;
                                // Regenerate fresh claims if possible and resign in
                                if (regenerateIdentityCallback != null)
                                {
                                    ClaimsIdentity identity = await regenerateIdentityCallback.Invoke(manager, user);
                                    if (identity != null)
                                    {
                                        var isPersistent = context.Properties.IsPersistent;
                                        AuthenticationProperties prop = new AuthenticationProperties();
                                        prop.AllowRefresh = true; //without this, will log out after 30 minutes
                                        prop.IsPersistent = isPersistent; //without this, will log out after 30 minutes, or whenever the browser session is ended
                                        context.OwinContext.Authentication.SignIn(prop, identity);
                                    }
                                }
                            }
                        }
                        if (reject)
                        {
                            context.RejectIdentity();
                            context.OwinContext.Authentication.SignOut(context.Options.AuthenticationType);
                        }
                    }
                }
            };
        }
    }
}

然后,假设您使用的是标准 MVC 项目,则可以通过在 Startup.Auth.cs 文件中将 SecurityStampValidator 更改为 MySecurityStampValidator 来使用它模板。

关于asp.net-mvc - ASP 身份登录 isPersistent 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28633142/

相关文章:

c# - .NET Core MVC 中的部分内容(用于视频/音频流)

asp.net - RouteConfig刷新页面时触发500错误

asp.net - 在服务器上找不到 System.Web.Helpers,怎么了?

javascript - 为什么 javascript 不能更好地支持 cookie 和查询字符串?

javascript - MarkLogic 应用程序服务器自定义登录页面 sessionID cookie 与 GET 请求

node.js - Node JS,express-session,从客户端浏览器中删除cookie

c# - 为什么 ASP.NET 的“记住我”功能如此健忘?

c# - 带有特殊字符的 ASP.NET MVC 身份电子邮件/用户名

c# - 使用身份提供者在 asp.net mvc 4 应用程序中添加角色

c# - HTTP 错误 401.0 - 未经授权的错误消息