【问题标题】:How to change the cookie ExpireTimeSpan in Asp.Net Identity after ConfigureAuth如何在 ConfigureAuth 之后更改 Asp.Net Identity 中的 cookie ExpireTimeSpan
【发布时间】:2024-01-21 07:00:02
【问题描述】:

我们有一个使用 Asp.Net 身份的产品,我们希望在其中配置 cookie 到期时间。 ExpireTimeSpan 当前在 Visual Studio 使用新项目为您创建的 Startup.ConfigureAuth 类中设置。这是在启动时从配置文件中获取时间,但我们希望能够从 webAPI 更改此值。 就目前而言,webAPI 请求可以修改配置文件,但我们需要回收应用程序池才能使其生效。

一旦服务器已经启动并运行,是否有任何方法可以更改此值?

我在这个主题上找到的只是这个问题ASP.NET Identity Change ExpireTimeSpan after ConfigureAuth,但它要求为单个会话更改它,而我想为整个服务器全局更改它。

更新:通过查看 Katana 源,我发现选项似乎存储在 Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware 类的公共属性中,但我不知道有任何方法可以获取对正在使用的对象的引用在我的应用中。

【问题讨论】:

    标签: c# asp.net asp.net-identity-2


    【解决方案1】:

    这需要一些时间才能弄清楚,但我相信我已经找到了正确的解决方案。这很有趣,因为我已经有了解决方案,只是没有探索范围内可用的选项。

    CookieAuthenticationOptions 只提供一个钩子,一个委托属性OnValidateIdentity

    OnValidateIdentity 会在每次有人登录(通过 cookie 身份验证提供程序)时出现,这恰好是运行一些自定义逻辑来确定他们新的过期时间的最佳时机。 它还允许您全局配置它。

    我已经对其进行了调试,可以确认配置选项的值坚持,并在未来全局登录时保留,直到应用程序池回收.并且过期的值覆盖在登录回调后适用于经过身份验证的用户。

    因此,由您决定价值的逻辑是什么,以及您是要在个人级别还是全局级别上进行设置。

    这里是代码示例,有助于更好地描绘这一点..

    public void ConfigureAuth(IAppBuilder app) {
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
        app.CreatePerOwinContext<ApplicationGroupManager>(ApplicationGroupManager.Create);
        app.CreatePerOwinContext<ApplicationDepartmentManager>(ApplicationDepartmentManager.Create);
    
        app.UseCookieAuthentication(new CookieAuthenticationOptions {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Login"),
            Provider = new CookieAuthenticationProvider {
    
                OnValidateIdentity = delegate(CookieValidateIdentityContext context) {
                    var stampValidator = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
                        validateInterval: TimeSpan.FromMinutes(15),
                        regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
                        getUserIdCallback: (id) => (id.GetUserId<int>())
                    );
                    Task result = stampValidator.Invoke(context);
    
                    bool found_custom_expiration = false;
                    int timeout = STATIC_CONFIG.DefaultSessionExpireMinutes;
                    DBHelper.Query(delegate (SqlCommand cmd) {
                        cmd.CommandText = @"
                            SELECT [value] 
                            FROM [dbo].[Vars] 
                            WHERE [FK_Department] = (
                                SELECT [Id] FROM [dbo].[ApplicationDepartments] WHERE [title] = 'Default'
                            ) 
                            AND [name]='Session Timeout'
                        ";
                        return cmd;
                    }, delegate (SqlDataReader reader) {
                        timeout = reader["value"].ToInt32();
                        found_custom_expiration = true;
                        return false;
                    });
                    if (found_custom_expiration) {
                        // set it at GLOBAL level for all users.
                        context.Options.ExpireTimeSpan = TimeSpan.FromMinutes(timeout);
                        // set it for the current user only.
                        context.Properties.ExpiresUtc = context.Properties.IssuedUtc.Value.AddMinutes(timeout);
                    }
                    // store it in a claim, so we can grab the remaining time later.
                    // credit: https://*.com/questions/23090706/how-to-know-when-owin-cookie-will-expire
                    var expireUtc = context.Properties.ExpiresUtc;
                    var claimType = "ExpireUtc";
                    var identity = context.Identity;
                    if (identity.HasClaim(c => c.Type == claimType)) {
                        var existingClaim = identity.FindFirst(claimType);
                        identity.RemoveClaim(existingClaim);
                    }
                    var newClaim = new System.Security.Claims.Claim(claimType, expireUtc.Value.UtcTicks.ToString());
                    context.Identity.AddClaim(newClaim);
                    return result;
                }
            },
            SlidingExpiration = true,
            // here's the default global config which was seemingly unchangeable.. 
            ExpireTimeSpan = TimeSpan.FromMinutes(STATIC_CONFIG.DefaultSessionExpireMinutes)
        });
    
        ApplicationHandler.OwinStartupCompleted();
    
    }
    

    这绝对可以改进为仅在尚未更改时才发布更改。而且您不必使用数据库查询,它可以是 XML 读取,或 web.config appsetting 或其他。 身份已经到位...因此您甚至可以访问 context.Identity 并对 ApplicationUser 执行某种自定义检查。

    所以...相关位...

    OnValidateIdentity = delegate(CookieValidateIdentityContext context) {
                var stampValidator = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
                    getUserIdCallback: (id) => (id.GetUserId<int>())
                );
                Task result = stampValidator.Invoke(context);
    
                int my_custom_minutes = 60; // run your logic here.
                    // set it at GLOBAL level for all (future) users.
                    context.Options.ExpireTimeSpan = TimeSpan.FromMinutes( my_custom_minutes );
                    // set it for the current user only.
                    context.Properties.ExpiresUtc = context.Properties.IssuedUtc.Value.AddMinutes( my_custom_minutes );
    
                return result;
    }
    

    【讨论】:

      最近更新 更多