引言
前文介紹了 Session-Cookie 的認證過程,簡單回顧下基本步驟:
- 客戶端(瀏覽器)向伺服器傳送使用者名稱和密碼
- 伺服器驗證透過後,建立 Session 物件,在 Session 中儲存該使用者相關的資料,比如使用者角色、登入時間等等
- 伺服器向使用者返回這個 Session 物件的唯一標識 SessionId,並寫入客戶端的 Cookie
- 客戶端隨後的每一次請求,都會透過 Cookie,將 SessionId 傳回伺服器
- 伺服器收到 SessionId,並據此找到 Session 物件,由此獲取到使用者資訊
這種方法的缺點就是分散式叢集情況下無法保證每臺伺服器都擁有相同的 Session,上篇文章也簡單介紹了幾種 Session 如何在多個伺服器之間共享的方法。
顯然,Session 的維護給服務端造成了很大的困擾,有沒有更好的方案,能不能直接不用 Session?
為此,Token 應運而生。
30s 圖解 Token 認證
首先,什麼是 Token?
簡單來說,Token 其實就是一串字串,一個令牌,客戶端訪問伺服器時,驗證透過後服務端會為其簽發一張令牌,之後,客戶端就可以攜帶這個令牌訪問伺服器,服務端只需要驗證令牌的有效性即可。
一般來說,Token 的組成是這樣的:
uid
(使用者唯一的身份標識) + time
(當前時間的時間戳) + sign
(簽名,Token 的前幾位以雜湊演算法壓縮成的一定長度的十六進位制字串)
基於 token 的認證步驟如下圖,配合文字食用:
1)客戶端(瀏覽器):使用者向伺服器傳送登入資訊(使用者名稱和密碼)來請求登入校驗;
2)服務端:驗證使用者名稱密碼等,驗證成功後生成 token 並返回給前端,這個 token 就是之後鑑權的唯一憑證。服務端需要將這個 token 及其對應的使用者資訊儲存在資料庫或者快取中;
3)客戶端:將服務端返回的 token 存在 cookie 或者 localStorge 中,之後的每次請求之前,從 cookie 或者 localStorge 取出 token 將其設定進 HTTP Header 中(可以透過 HTTP 請求攔截器實現);
4)服務端:服務端接收到來自客戶端的請求,從 HTTP Header 中取出 token,去快取或者資料庫中進行驗證(該 token 是否存在 / 根據該 token 能否找到對應的使用者),如果驗證透過則執行進一步的業務操作,如果不透過則拒絕執行。
附加閱讀
Token 認證服務端程式碼
先來看登入,就是先判斷使用者名稱密碼是否正確,如果正確,那麼會生成並返回一個字串做為 token(這裡偷個懶就直接用 UUID 來生成了),並將其和使用者資訊(這裡就簡單的存了 username)一併存入到資料庫 or 快取中(這裡採用 Redis,過期時間可自行配置)。
退出登入實質就是刪除 Redis 中儲存的 token,完整內容如下:
再來個攔截器,前端拿到後端返回的 token 後每次請求前都會在 HTTP header 中帶上這個 token,服務端設定個攔截器取出 Header 中的token,然後去 Redis 中進行判斷這個 token 是否存在,若存在則允許進行下一步操作,:
Refresh Token
一般來說,為了安全起見,防止 token 被攻擊者盜用,token 的有效期不會設定的太長,這樣就會由於 token 過期導致使用者需要重新登入從而生成新的 token。
如何才能做到不需要使用者去頻繁的登入呢,Refresh Token 機制出現了。
我們把之前的那個 Token 稱之為 Access Token,業務介面用這個 Access Token 進行認證鑑權
而 Refresh Token 呢,就是一個專門用來在 Access Token 過期後重新獲取新的 Access Token 的 Token
Refresh Token 的過期時間設定的長一點比如一兩個月,Access Token 的過期時間設定短一點比如一週,這樣可以縮短 Access Token 的過期時間保證安全,同時又不會因為頻繁過期重新要求使用者登入
具體認證步驟如下圖,配合文字食用:
1)客戶端(瀏覽器):使用者向伺服器傳送登入資訊(使用者名稱和密碼)來請求登入校驗;
2)服務端: 驗證使用者名稱密碼等,驗證成功後生成 Access Token 和 Refresh Token 並返回給前端,服務端需要將這兩個 token 及其對應的使用者資訊儲存在資料庫或者快取中;
3)客戶端: 將服務端返回的 Access Token 和 Refresh Token 存在 cookie 或者 localStorge 中,之後的每次請求之前,從 cookie 或者 localStorge 取出 Access Token
將其設定進 HTTP Header 中(可以透過 HTTP 請求攔截器實現);
4)服務端:
- 驗證 Access Token 有效:正常返回資料
- 驗證 Access Token 過期:拒絕請求
- 客戶端:重新發起請求,在 HTTP Header 中攜帶 Refresh Token 傳送給服務端
- 服務端:驗證客戶端傳來的 Refresh Token ,驗證成功後生成新的 Access Token 並返回給客戶端
- 客戶端:獲得服務端返回的新的 Access Token,重新發起請求並攜帶新的 Access Token
如何理解 Refresh Token 的必要性,或者說為什麼使用 Refresh Token 能夠更安全?
- Access Token 每次訪問都要帶著,因此更容易被盜取
- 而 Refresh Token 客戶端獲取到之後就儲存起來,Access Token 失效之後,才會用到 Refresh Token,所以粗略來說 Refresh Token 只會在網路上傳輸兩次,一次是你獲取的時候,一次是你使用的時候(從上圖可以看出來),因此 Refresh Token 被盜的風險遠遠小於 Access Token
小夥伴們大家好呀,本文首發於公眾號@飛天小牛肉,阿里雲 & InfoQ 簽約作者,分享大廠面試原創高質量題解、原創技術乾貨和成長經驗。回覆『
春秋招
』我拉你進求職吹水交流群,回覆『簡歷修改
』免費獲取簡歷修改服務,回覆『Echo
』免費獲取社群專案手把手教程)收留 2023 秋招傷心人,秋招補錄 & 春招強勢開啟,現在不投年後要被衝爛啦,資訊彙總長期更新:小牛肉 x 網際網路春招 & 秋招補錄資訊彙總