【发布时间】:2014-05-30 05:16:48
【问题描述】:
我想根据 OWIN cookie 的过期时间创建某种倒数计时器。我将 OWIN 与 MVC 5 一起使用,据我所知,默认情况下 SlidingExpiration 处于打开状态。我不使用“会话”,因为我需要这个应用程序存在于网络场中(我不打算部署会话数据库)。
【问题讨论】:
-
这不可能吗?
标签: .net asp.net-mvc-5 session-cookies owin
我想根据 OWIN cookie 的过期时间创建某种倒数计时器。我将 OWIN 与 MVC 5 一起使用,据我所知,默认情况下 SlidingExpiration 处于打开状态。我不使用“会话”,因为我需要这个应用程序存在于网络场中(我不打算部署会话数据库)。
【问题讨论】:
标签: .net asp.net-mvc-5 session-cookies owin
我只想建立在第一个答案的基础上,我在使用自定义用户商店时遇到了问题。虽然实现对我自己来说似乎更简单
public static class ApplicationCookieValidateIdentityContext
{
public static Task ApplicationValidateIdentity(CookieValidateIdentityContext context)
{
var identity = context.Identity;
if (identity.HasClaim(c => c.Type == "expires"))
{
var existingClaim = identity.FindFirst( "expires");
identity.RemoveClaim(existingClaim);
}
if (context.Properties.ExpiresUtc == null) return Task.FromResult(0);
context.Identity.AddClaim(new Claim("expires", context.Properties.ExpiresUtc.ToString()));
return Task.FromResult(0);
}
}
我还创建了一个过滤器,将过期时间添加到 cookie
// make sure its defaulted because the claim is not set on the login callback
var expires = DateTimeOffset.Now.AddMinutes(
Convert.ToDouble(ConfigurationManager.AppSettings["SessionTimeInMinutes"]));
if (identity.HasClaim(c => c.Type == "expires"))
{
expires = DateTimeOffset.Parse(identity.FindFirstValue("expires"));
}
cookieHeaderValues.Add(new SessionCookeHeaderValue("expiresAt", expires.ToString("O"), expires));
【讨论】:
SlidingExpiration 考虑在内的解决方案stackoverflow.com/a/59038642/338456
您只需在 cookie 验证阶段获取CookieValidateIdentityContext。一旦你得到它,提取你需要的任何东西并将它们保存为Claim或你喜欢的其他方式。
对于带有 Asp.NET Identity 2.0 的 MVC 5,您需要执行两个步骤:
定义自定义OnValidateIdentity,提取cookie信息,保存为Claim。
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = MyCustomValidateIdentity //refer to the implementation below
}
}
}
// this method will be called on every request
// it is also one of the few places where you can access unencrypted cookie content as CookieValidateIdentityContext
// once you get cookie information you need, keep it as one of the Claims
// please ignore the MyUserManager and MyUser classes, they are only for sample, you should have yours
private static Task MyCustomValidateIdentity(CookieValidateIdentityContext context)
{
// validate security stamp for 'sign out everywhere'
// here I want to verify the security stamp in every 100 seconds.
// but I choose not to regenerate the identity cookie, so I passed in NULL
var stampValidator = SecurityStampValidator.OnValidateIdentity<MyUserManager<Myuser>. MyUser>(TimeSpan.FromSeconds(100), null);
stampValidator.Invoke(context);
// here we get the cookie expiry time
var expireUtc = context.Properties.ExpiresUtc;
// add the expiry time back to cookie as one of the claims, called 'myExpireUtc'
// to ensure that the claim has latest value, we must keep only one claim
// otherwise we will be having multiple claims with same type but different values
var claimType = "myExpireUtc";
var identity = context.Identity;
if(identity.HasClaim(c=> c.Type == claimType))
{
var existingClaim = identity.FindFirst(claimType);
identity.RemoveClaim(existingClaim);
}
var newClaim = new Claim(claimType, expireUtc.Value.UtcTicks.ToString());
context.Identity.AddClaim(newClaim);
return Task.FromResult(0);
}
}
在您的控制器方法中访问您的 Claim
// since expiry time has now become part of your claims, you now can get it back easily
// this example just returns the remaining time in total seconds, as a string value
// assuming this method is part of your controller methods
public string RemainingTime()
{
var identity = User.Identity as ClaimsIdentity;
var claimType = "myExpireUtc"; //NOTE: must be the same key value "myExpireUtc" defined in code shown above
if(identity != null && identity.HasClaim(c=> c.Type == claimType))
{
var expireOn = identity.FindFirstValue(claimType);
DateTimeOffset currentUtc = DateTimeOffset.UtcNow;
DateTimeOffset? expireUtc = new DateTimeOffset(long.Parse(expireOn), TimeSpan.Zero);
var remaining = (expireUtc.Value - currentUtc).TotalSeconds;
return remaining.ToString();
}
return string.Empty;
}
我使用这种方法来提醒我的应用程序用户在会话超时之前延长他们的会话。
感谢这篇文章How do I access Microsoft.Owin.Security.xyz OnAuthenticated context AddClaims values?
【讨论】:
stampValidator.Invoke(context); 是等待的,应该等待!因此,我遇到了令人讨厌的例外;)