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