HTTP 是一個無狀態的協議,一次請求結束後,下次在發送服務器就不知道這個請求是誰發來的了(同一個 IP 不表明同一個用戶),在 Web 應用中,用戶的認證和鑑權是很是重要的一環,實踐中有多種可用方案,而且各有千秋。算法
在 Web 應用發展的初期,大部分採用基於 Session 的會話管理方式,邏輯以下。數據庫
基於 Session 的方式存在多種問題。json
鑑於基於 Session 的會話管理方式存在上述多個缺點,無狀態的基於 Token 的會話管理方式誕生了,所謂無狀態,就是服務端再也不存儲信息,甚至是再也不存儲 Session,邏輯以下。跨域
基於 Token 的會話管理方式有效解決了基於 Session 的會話管理方式帶來的問題。瀏覽器
JWT 是 JSON Web Token 的縮寫,JWT 自己沒有定義任何技術實現,它只是定義了一種基於 Token 的會話管理的規則,涵蓋 Token 須要包含的標準內容和 Token 的生成過程。緩存
一個 JWT Token 長這樣。bash
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDQ1MTE3NDMsImp0aSI6IjYxYmVmNjkyLTE4M2ItNGYxYy1hZjE1LWUwMDM0MTczNzkxOSJ9.CZzB2-JI1oPRFxNMaoFz9-9cKGTYVXkOC2INMoEYNNA
複製代碼
仔細辨別會發現它由 A.B.C
三部分組成,這三部分依次是頭部(Header)、負載(Payload)、簽名(Signature),頭部和負載以 JSON 形式存在,這就是 JWT 中的 JSON,三部分的內容都分別單獨通過了 Base64 編碼,以 .
拼接成一個 JWT Token。服務器
JWT 的 Header 中存儲了所使用的加密算法和 Token 類型。架構
{
"alg": "HS256",
"typ": "JWT"
}
複製代碼
Payload 是負載,JWT 規範規定了一些字段,並推薦使用,開發者也能夠本身指定字段和內容,例以下面的內容。app
{
username: 'yage',
email: 'sa@simpleapples.com',
role: 'user',
exp: 1544602234
}
複製代碼
須要注意的是,Payload的內容只通過了 Base64 編碼,對客戶端來講當於明文存儲,因此不要放置敏感信息。
Signature 部分用來驗證 JWT Token 是否被篡改,因此這部分會使用一個 Secret 將前兩部分加密,邏輯以下。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
複製代碼
JWT 擁有基於 Token 的會話管理方式所擁有的一切優點,不依賴 Cookie,使得其能夠防止 CSRF 攻擊,也能在禁用 Cookie 的瀏覽器環境中正常運行。
而 JWT 的最大優點是服務端再也不須要存儲 Session,使得服務端認證鑑權業務能夠方便擴展,避免存儲 Session 所須要引入的 Redis 等組件,下降了系統架構複雜度。但這也是 JWT 最大的劣勢,因爲有效期存儲在 Token 中,JWT Token 一旦簽發,就會在有效期內一直可用,沒法在服務端廢止,當用戶進行登出操做,只能依賴客戶端刪除掉本地存儲的 JWT Token,若是須要禁用用戶,單純使用 JWT 就沒法作到了。
既然 JWT 依然存在諸多問題,甚至沒法知足一些業務上的需求,可是咱們依然能夠基於 JWT 在實踐中進行一些改進,來造成一個折中的方案,畢竟,在用戶會話管理場景下,沒有銀彈。
前面講的 Token,都是 Access Token,也就是訪問資源接口時所須要的 Token,還有另一種 Token,Refresh Token,一般狀況下,Refresh Token 的有效期會比較長,而 Access Token 的有效期比較短,當 Access Token 因爲過時而失效時,使用 Refresh Token 就能夠獲取到新的 Access Token,若是 Refresh Token 也失效了,用戶就只能從新登陸了。
在 JWT 的實踐中,引入 Refresh Token,將會話管理流程改進以下。
將生成的 Refresh Token 以及過時時間存儲在服務端的數據庫中,因爲 Refresh Token 不會在客戶端請求業務接口時驗證,只有在申請新的 Access Token 時纔會驗證,因此將 Refresh Token 存儲在數據庫中,不會對業務接口的響應時間形成影響,也不須要像 Session 同樣一直保持在內存中以應對大量的請求。
上述的架構,提供了服務端禁用用戶 Token 的方式,當用戶須要登出或禁用用戶時,只須要將服務端的 Refresh Token 禁用或刪除,用戶就會在 Access Token 過時後,因爲沒法獲取到新的 Access Token 而再也沒法訪問須要認證的接口。這樣的方式雖然會有必定的窗口期(取決於 Access Token 的失效時間),可是結合用戶登出時客戶端刪除 Access Token 的操做,基本上能夠適應常規狀況下對用戶認證鑑權的精度要求。
JWT 的使用,提升了開發者開發用戶認證鑑權功能的效率,下降了系統架構複雜度,避免了大量的數據庫和緩存查詢,下降了業務接口的響應延遲。然而 JWT 的這些優勢也增長了 Token 管理上的難度,經過引入 Refresh Token,既能繼續使用 JWT 所帶來的優點,又能使得 Token 管理的精度符合業務的需求。