这花了一些时间来弄清楚,但我相信我已经找到了正确的解决方案。这很有趣,因为我已经有了解决方案,只是没有探索范围内可用的选项。
CookieAuthenticationOptions
只提供一个钩子,一个委托属性OnValidateIdentity
.
The OnValidateIdentity
每次有人登录(通过 cookie 身份验证提供程序)时都会发生,这恰好是运行一些自定义逻辑来确定新的到期时间的最佳时机。
它还允许您进行全局配置。
我已经调试过了并且可以确认配置选项的值sticks,并保留以供将来登录globally直到应用程序池回收。此外,过期值覆盖适用于登录回调后经过身份验证的用户。
因此,由您决定什么逻辑决定该值,以及您是否想要在个人级别或全局级别上设置它。
这是代码示例,可帮助更好地描述这一点。
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://stackoverflow.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;
}