讨论一下.NET里,对cookie身份验证的超时的处理
引言
在.NET里提供了FormsAuthentication类用来对用户身份进行验证和授权。不过,对于cookie的超时处理,一直是一个头疼的问题。这里介绍一下微软对.NET 身份验证超时的处理机制,不过我相信,这个机制并不是.NET所独有的,在你用任何语言(例如Java,Php,JS)等都会遇到这个问题,只是很多时候,我们不太在意这个问题。
问题的提出
我们通常使用cookie存放一下用户身份的信息,当然这些信息是加密的,然后输出到客户端,当用户提交时,在从cookie里获取这些信息,然后解密。其中很重要的一步是判断cookie有没有超时。考虑下面一种情况:一个用户于: 2020.3.9 10:00:00 登录一个系统,假设cookie的有效期为1个小时,也就是说 cookie将于 2020.3.9 11:00:00 失效。所以,服务器只要根据这个时间判断cookie是否失效即可,但是这个方式没有考虑时区。
例如:你的服务器是在“日本”,一个中国用户和一个美国用户访问该网站,登录后,服务器往这2个用户电脑上输出cookie,但是中美时区的不同,导致同一时刻,这2个用户看到的cookie日期出现了不同。因此,为了简化计划,在微软的.NET里,统一使用UTC时间,也就是世界标准时间。
在微软.NET的源代码里,给出了很大的注释来介绍这个问题。
参考上面注释,就算使用UTC时间,仍然还有一些问题。
简单解释一下上图代码里的注释:为了方便.NET对时间处理,.NET时间统一采用UTC世界标准时,这样,一个北京用户 2020.3.9 10:00:00 登录系统,因为在+8区,所以,会在标准时的基础上加上+8,另外一个用户会在标准时的基础上-8,大致是这样的意思。
但是,不是每个开发者,每种开发语言都会采用类似这样的策略,.NET还需要考虑扩展性,因此,时间大致分文三种:
1.DateTime是UTC时间,这种最简单,直接处理。
2.DateTime是本地时间,.NET Framework会把他转换为UTC时间,同时,DateTime类在设计时预留了一个隐藏字段,他可以处理自定义时间(下述)。
3.DateTime的类型未知,考虑和早期.NET1.1兼容性,就把他归类为本地时间。
自定义夏令时
自定义时区曾经在中国使用过。正式的名称叫做“北京夏令时”,中国在1986年-1991年间实施的一种夏季时间制度,北京夏令时比标准的北京时间早一个小时。
夏令时,主要解决“感官”问题,例如:冬天的北京,晚上19:00 新闻联播时,天已经黑了,而夏天的北京,19:00天还亮,为了让夏天的北京19:00天也变黑,那时间往后退一个小时。
同样的还有美国时间,PDT是指太平洋夏季时间,PST是指太平洋标准时间。
从地缘政治上说,中国采用的是统一+8区,看地图都知道,中国地域广,全国使用同一时间可能并不是合理,
因为如果规定全国都是早上8点上班,可能东部的山东青岛已经天大亮,而西藏的日喀则可能还是深夜。同样,晚上8点东部天黑了,而西部天还是下午。
但是,北京夏令时的人为拨动时间,确实会打乱生成,因此在1991年停止使用。
但是在有些国家还是使用的,为此,DateTime类在设计时,包含了一个隐藏字段,来自定义夏令时。通过DateTimeOffset 属性校对时间。
绝对到期与顺滑到期
cookie过期的第二个问题是绝对过期与顺滑过期。如上 用户与 2020.3.9 10:00:00 登录系统,2020.3.9 11:00:00 cookie到期,这种记录方法被成为“绝对时间”,简单但是粗暴。试想一个用户在写一篇问题,他在
2020.3.9 11:00:01提交时,系统突然提示,身份过期,然后跳转到登录页面,所写的内容全部丢失,估计用户会欲哭无泪。(当然现在都有ajax在暗地里验证,不会出现这种问题了)。
在.NET里给出了一个 SlidingExpiration 属性,他会让cookie过期进行动态延长。默认值为true,
什么意思呢?下面是MSDN的解释: 如果发出了请求并且超过了一半的超时时间间隔,则滑动过期会重置有效身份验证 cookie 的过期时间。 如果 cookie 过期,用户必须重新进行身份验证。
也就是,虽然你的cookie会于2020.3.9 11:00:00 过期,但是.NET系统会自动给你延长。
OnAuthenticate事件
知道延长cookie,接着就就要选择在何时修改这个cookie事件。OnAuthenticate是身份验证事件,利用这个事件是再好不过的了。
在代码实现方面,如果查看.NET源代码,可以看到系统提供了 RenewTicketIfOld 方法,然后把这个方法注入到 OnAuthenticate事件,来动态延长。
https://referencesource.microsoft.com/#System.Web/Security/FormsAuthentication.cs,629
整个实现算法还是比较复杂的。需要考虑的细节太多。例如有些浏览器禁止使用cookie等情况。当然,这些复杂情况微软都被我们做了,我们直接用即可。