揭祕 Cookie、Session、JWT 之間的關係
登錄認證是任何系統中避不開的一個話題,登錄認證隨着系統架構的演變而出現與架構相適應的方案。下面介紹架構演變過程中登錄常客 Cookie、Session、JWT 之間的關係。
1、單體架構
單體架構階段下,前端代碼和後端代碼都在一個項目中,也就不存在跨域問題。此時的登錄認證機制採用的是 Cookie 和 Session 的方式進行。認證的方式如下:
用戶訪問的服務器的時候,攜帶服務器給予的 sessionId 到後端,後端拿到 sessionId 之後就可以拿到登錄用戶的信息。
2、前 / 後端分離
單點的架構中前端和後端代碼都在一個項目中,對開發人員的開發、業務部署都帶來了阻力,於是就出現了前後端分離模式,如下的前後端分離模式圖:
前後端分離模式中出現了跨域問題,跨域使得瀏覽器和服務器數據交互受到阻礙,並且也無法獲取 Cookie 中的 sessionId 了。如果想要通過 Cookie 和 Session 方式來實現登錄認證,那麼就要解決跨域問題,此時就有了跨域資源共享(CORS)。CORS 的流程如下:
通過 CORS 解決了跨域問題之後,登錄認證的方式繼續使用 Cookie 和 Session 方式來完成。
3、分佈式系統
隨着業務發展的發展,單個系統拆分成多個子系統並且子系統部署多臺服務,此時的服務與服務之間的 session 是不共享的,如果想要採用 cookie 和 session 方式實現登錄認證功能,那麼就要解決 session 共享的問題。
業界主流使用的是單點登錄來解決分佈式下的 session 共享問題,其流程如下所示:
(1)用戶請求訂單服務的時候,訂單服務發現其沒有登錄,於是請求認證中心進行認證。
(2)認證中心彈出登錄頁讓用戶填寫賬號和密碼,認證系統對其賬號與密碼進行驗證,驗證通過之後把登錄狀態寫入 SSO 的 session 中,同時瀏覽器也會寫入 SSO 的 Cookie 中。
(3)SSO 登錄系統完成以後生成 ticket,然後跳轉到訂單服務上,同時把 ticket 作爲參數傳遞給訂單服務上,訂單服務拿到 ticket 後從後臺向 SSO 發送請求來驗證 ticket 是否有效,驗證通過後訂單服務把登錄狀態寫入到 session 中並設置訂單服務域下的 Cookie。
通過以上的步驟就實現了跨域的單點登錄,後面再訪問訂單服務的時候,訂單服務上就是登錄狀態。
(4)用戶此時想訪問商品服務,商品服務沒有登錄就會跳轉到 SSO 上,由於 SSO 在用戶訪問訂單服務的後已經是登錄狀態了,所以不需要重新登錄驗證。
(5)SSO 會生成 ticket 給商品服務,瀏覽器會跳轉到商品服務上並把 ticket 作爲參數傳遞給商品服務,商品服務拿到 ticket 後再去後臺訪問 SSO 驗證 ticket 的有效性,SSO 驗證通過後商品服務把登錄狀態寫入 session 中並在瀏覽器中寫入商品域的 Cookie。
下面介紹一種使用 Redis 和 Cookie 實現的單點登錄的設計方案,具體的實現流程圖如下所示:
4、分佈式系統下的去中心化認證
Cookie 和 Session 機制、Cookie 和 Redis 機制都需要服務器需要維護一個會話或者組件來標識這些用戶已經登錄;那麼是否存在一種認證方式直接就可以從請求中知道這個用戶是哪個人呢?由於就出現了無狀態登錄,典型的實現方案是 JWT 機制,JWT 機制的工作原理如下:
無狀態登錄最大的優勢在於系統的水平擴展性強,因爲服務器不需要維護每個用戶的登錄信息,所以可以非常方便的爲這個集羣增加實例。
無狀態登錄的最大問題就是沒有辦法註銷,一旦令牌頒發出去了,除非令牌自己過期了否則令牌會一致有效,所以設計中需要增加 Redis 來輔助實現強制的註銷的功能。
總結:
(1)Cookie 和 Session 機制是實現登陸認證的基本方式,隨着系統的不斷演變,於是單體架構下的這套認證機制失效了,爲了適應這套認證流程出現了不同的解決方案來保證認證流程正常的使用。
(2)Cookie 和 Session 機制是有狀態的登陸,爲了適應一些特定的場景,出現了無狀態登陸機制(JWT)。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Y5MWj66Ujc3Jj7UKoa7VNw