奇怪的表单身份验证过期行为导致 DST 结束
本文关键字:DST 结束 过期 表单 身份验证 | 更新日期: 2023-09-27 18:20:47
我有一个使用表单身份验证的 ASP.NET Web 应用程序。我们在 10 月 25 日凌晨 1 点至凌晨 2 点之间在我们的实时网站上目睹了一些奇怪的行为(在英国,DST 在 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 点时,问题就解决了。
在我的测试过程中,我添加了一些额外的日志记录来确定故障点(也是在最初创建身份验证票证之后(ticket.Expiration
和DateTime.Now
的值。结果是:
在 DST 结束之前:
服务器时间:00:53:39
DateTime.Now
= 00:53:39
ticket.Expiration
= 01:33:37(正确(
在 DST 结束之前:
服务器时间:01:25:08
DateTime.Now
= 01:25:08
ticket.Expiration
= 01:05:08(错误(
夏令时结束后:
服务器时间:01:35:06
DateTime.Now
= 01:35:06
ticket.Expiration
= 02:15:06(正确(
因此,似乎在 DST 结束前一小时内,从 FormsAuthenticationTicket
Expiration
属性返回的时间晚了一个小时。我知道过期时间在内部存储为 UTC,但 Expiration
属性是本地时间,并且怀疑转换存在问题。
知道为什么会这样吗?代码问题?服务器问题?
问题的症结就在这里:
if (ticket.Expiration < DateTime.Now)
将其更改为:
if (ticket.Expiration.ToUniversalTime() < DateTime.UtcNow)
或者更好的是,它在内部做同样的事情:
if (ticket.Expired)
该问题实际上在 MSDN 参考源中找到的注释中详细描述。
基本上,它归结为DateTime
结构的设计。 比较两个DateTime
对象仅考虑其Ticks
值,而不考虑其Kind
,因此不考虑DST或时区。
另外,我通常建议不要使用 ToUniversalTime
,但在这种特殊情况下,没关系。