討論一下.NET里,對cookie身份驗證的超時的處理
- 2020 年 3 月 9 日
- 筆記
引言
在.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等情況。當然,這些複雜情況微軟都被我們做了,我們直接用即可。