10.06 由Session到Token的身份驗證演變過程理解Session、Cookie、Token

由Session到Token的身份驗證演變過程理解Session、Cookie、Token

本文將從Web應用 由傳統身份驗證基於Token的身份驗證的演變過程的角度,介紹Session、Cookie、Token。


很久以前,Web 應用基本用作文檔的瀏覽,如網絡黃頁。既然僅僅是瀏覽,因此服務器不需要記錄具體用戶在某一段時間裡都瀏覽了哪些文檔,每次請求都是一個新的HTTP協議,對服務器來說都是全新的。

基於Session的身份驗證

隨著交互式Web應用的興起,比如,購物等需要登錄的網站。引出了一個新的問題,那就是要記錄哪些用戶登錄了系統進行了哪些操作,即要管理會話(什麼是會話?簡單的講如果用戶需要登錄,那麼就可以簡單的理解為會話,如果不需要登錄,那麼就是簡單的連接。),比如,不同用戶將不同商品加入到購物車中, 也就是說必須把每個用戶區分開。因為HTTP請求是無狀態的,所以想出了一個辦法,那就是給每個用戶配發一個

會話標識(Session id),簡單的講就是一個既不會重複,又不容易被找到規律以仿造的隨機字符串,使得每個用戶的收到的會話標識都不一樣, 每次用戶從客戶端向服務端發起HTTP請求的時候,把這個字符串給一併發送過來, 這樣服務端就能區分開誰是誰了,至於客戶端(瀏覽器)如何保存這個“身份標識”,一般默認採用 Cookie 的方式,這個會話標識(Session id)會存在客戶端的Cookie中。

雖然這樣解決了區分用戶的問題,但又引發了一個新的問題,那就是每個用戶(客戶端)只需要保存自己的會話標識(Session id),而服務端則要保存所有用戶的會話標識(Session id)。 如果訪問服務端的用戶逐漸變多, 就需要保存成千上萬,甚至幾千萬個,這對服務器說是一個難以接受的開銷 。 再比如,服務端是由2臺服務器組成的一個集群, 小明通過服務器A登錄了系統, 那session id會保存在服務器A上, 假設小明的下一次請求被轉發到服務器B怎麼辦? 服務器B可沒有小明 的 session id。

可能會有人講,如果使小明登錄時,始終在服務器A上進行登錄(sticky session),豈不解決了這個問題?那如果服務器A掛掉怎麼辦呢? 還是會將小明的請求轉發到服務器B上。

如此一來,那隻能做集群間的 session 複製共享了, 就是把 session id 在兩個機器之間進行復制,如下圖,但這對服務器的性能和內存提出了巨大的挑戰。

由Session到Token的身份驗證演變過程理解Session、Cookie、Token

因此,又想到如果將所有用戶的Session集中存儲呢,也就想到了緩存服務Memcached——由於 Memcached 是分佈式的內存對象緩存系統,因此可以用來實現 Session 同步。把session id 集中存儲到一臺服務器上, 所有的服務器都來訪問這個地方的數據, 如此就避免了複製的方式, 但是這種“集萬千寵愛於一身”使得又出現了單點故障的可能, 就是說這個負責存儲 session 的服務器掛了, 所有用戶都得重新登錄一遍, 這是用戶難以接受的。

由Session到Token的身份驗證演變過程理解Session、Cookie、Token

那麼索性存儲Session的服務器也搞成集群,增加其可靠性,避免單點故障,但不管如何,Session 引發出來的問題層出不窮。

於是有人就在思考, 為什麼服務端必須要保存這session呢, 只讓每個客戶端去保存不行嗎?可是服務端如果不保存這些session id ,又將如何驗證客戶端發送的 session id 的確是服務端生成的呢? 如果不驗證,服務端無法判斷是否是合法登錄的用戶,對,這裡的問題是驗證, session 只是解決這個驗證問題的而產生的一個解決方案,是否還有其它方案呢?

基於Token 的身份驗證

例如, 小明已經登錄了系統,服務端給他發一個令牌(Token), 裡邊包含了小明的 user id, 後續小明再次通過 Http 請求訪問服務器的時候, 把這個 Token 通過 Http header 帶過來不就可以了。

服務端需要驗證 Token是自己生成的,而非偽造的。假如不驗證任何人都可以偽造,那麼這個令牌(token)和 session id沒有本質區別,如何讓別人偽造不了?那就對數據做一個簽名(Sign)吧, 比如說服務端用 HMAC-SHA256 加密算法,再加上一個只有服務端才知道的密鑰, 對數據做一個簽名, 把這個簽名和數據一起作為 Token 發給客戶端, 客戶端收到 Token 以後可以把它存儲起來,比如存儲在 Cookie 裡或者 Local Storage 中,由於密鑰除了服務端任何其他用戶都不知道, 就無法偽造令牌(Token)。

由Session到Token的身份驗證演變過程理解Session、Cookie、Token

如此一來,服務端就不需要保存 Token 了, 當小明把這個Token發給服務端時,服務端使用相同的HMAC-SHA256 算法和相同的密鑰,對數據再計算一次簽名, 和 Token 中的簽名做個對比, 如果相同,說明小明已經登錄過了, 即驗證成功。若不相同, 那麼說明這個請求是偽造的。

由Session到Token的身份驗證演變過程理解Session、Cookie、Token

這樣一來, 服務端只需要生成 Token,而不需要保存Token, 只是驗證Token就好了 ,也就實現了時間換取空間(CPU計算時間換取session 存儲空間)。沒了session id 的限制, 當用戶訪問量增大, 直接加機器就可以輕鬆地做水平擴展,也極大的提高了可擴展性。


由Session到Token的身份驗證演變過程理解Session、Cookie、Token


分享到:


相關文章: