我有一个使用表单身份验证的ASP.NET Web应用程序。我们在10月25日凌晨1点至凌晨2点(在英国,夏令时结束于2015年10月25日凌晨2点,时钟返回了一个小时)的实时网站上目睹了一些奇怪的行为,所有用户都注销了身份验证票,将由以下代码过期:
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpCookie cookie = Request.Cookies["MyCookie"];
FormsAuthenticationTicket ticket;
try
{
ticket = FormsAuthentication.Decrypt(cookie.Value);
}
catch
{
this.RedirectDueToError(ErrorView);
return;
}
if (ticket == null) { return; }
if (ticket.Expiration < DateTime.Now)
{
this.RedirectDueToError(TimeoutView);
}
}
Web.config包含:
<authentication mode="Forms">
<forms name="MyCookie" timeout="40" requireSSL="false"/>
</authentication>
我已经在测试服务器上重现了该问题,可以看到该问题在DST结束之前的凌晨1点到凌晨2点之间发生。当时间到达凌晨2点并自动改回1个小时到凌晨1点时,问题就解决了。
在测试过程中,我添加了一些额外的日志记录来确定故障点(也是在最初创建身份验证票证之后)的
ticket.Expiration
和DateTime.Now
的值。结果是:在DST结束之前:
服务器时间:00:53:39
DateTime.Now
= 00:53:39ticket.Expiration
= 01:33:37(正确)在DST结束之前:
服务器时间:01:25:08
DateTime.Now
= 01:25:08ticket.Expiration
= 01:05:08(错误)DST发布结束:
服务器时间:01:35:06
DateTime.Now
= 01:35:06ticket.Expiration
= 02:15:06(正确)因此,似乎在DST结束前的一个小时,从
FormsAuthenticationTicket
Expiration
属性返回的时间要晚一个小时。我知道到期时间在内部存储为UTC,但是Expiration
属性是本地时间,并且怀疑转换中存在问题。任何想法为什么会这样?代码问题?服务器问题?
最佳答案
问题的症结在这里:
if (ticket.Expiration < DateTime.Now)
将此更改为:
if (ticket.Expiration.ToUniversalTime() < DateTime.UtcNow)
或对此更好,它在内部做同样的事情:
if (ticket.Expired)
问题实际上是详细地in the comments found in the MSDN reference sources详细描述的。
基本上,它取决于
DateTime
结构的设计。比较两个DateTime
对象仅考虑其Ticks
值,而不考虑其Kind
,因此它不考虑DST或时区。另外,我通常建议不要使用
ToUniversalTime
,但是在这种情况下,可以。关于c# - 奇怪的表单例份验证到期行为导致DST结束,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33567912/