一、JWT簡介
JWT(JSON WEB TOKEN)是一個基于JSON的公開規範(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對象在各方之間安全地傳輸資訊。該資訊使用了數字簽名,可以被驗證與信任。
二、應用場景
- Authorization(授權):JWT最常見的應用場景,一旦使用者登入,後續每個請求都将包含JWT,允許使用者通路該令牌允許的路由、服務和資源。單點登入是現在廣泛使用的JWT的一個特性,因為它的開銷很小,并且可以輕松地跨域使用。
- Information Exchange (資訊交換) : JWT也可用于在各方之間安全的傳輸資訊 。因為JWT使用了數字簽名。例如,使用公鑰/私鑰對,就可對發送人加以驗證。另外,簽名是使用請求頭和求求内容計算得到的,是以還可以驗證内容沒有被篡改。
三、JWT的結構
JSON Web Token由三部分組成,它們之間用圓點(.)連接配接。這三部分分别是:
- Header
- Payload
-
Signature
一個典型的JWT的形式如下所示:
aaaa.bbbbbbbbbb.cccccc
具體到每一部分:
1. Header
Header典型的由兩部分組成:token的類型(“JWT”)和算法名稱(比如:HMAC SHA256或者RSA等等)。
{
'alg': "HS256",
'typ': "JWT"
}
然後,用Base64對這個JSON編碼就得到JWT的第一部分.
2. Payload
JWT的第二部分是payload,它是關于實體(通常是使用者)和其他資料的聲明。聲明有三種類型: registered, public 和 private。
- Registered claims : 這裡有一組預定義的聲明,使用時推薦,但不強制。比如:iss (issuer 釋出者), exp(expiration time 有效期), sub (subject 主題), aud (audience)等。
- Public claims : 此類型聲明可以随意定義。
-
Private claims : 不屬于公開或者注冊的聲明,用在各方約定好并同意在各方之間共享資訊所使用的聲明。
一個示例:
{
"exp":1625309676,
"user_name":"liuzhihao",
"jti":"2ddc8367-b4ba-448b-a282-c52cc04c289d",
"client_id":"browser",
"scope":[
"all"
],
"ip":"172.21.72.116"
}
用Base64對Payload這個JSON編碼就得到JWT的第二部分。
由于base64可被解碼因而被擷取到所包含的資訊,是以不建議在payload或header中放置敏感資訊,除非它們是加密的。
3. Signature
将編碼過的header與編碼過的payload使用header所聲明的算法名稱對它們簽名,即可得到第三部分。
格式示例:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
簽名用于驗證消息在傳遞過程中有沒有被更改,而且對于使用私鑰簽名的token,它還可以驗證JWT的發送方的身份。
生成一條完整的JWT示例:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2csUTUU5keZpnT3FleYhnRzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcuMzNwUjNwkTMzAjNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
四、JWT的使用
在認證時,當使用者用他們的憑證成功登入以後,會擷取到一個傳回的JWT。此後,Token就是使用者憑證了,但必須小心防止出現安全問題。一般而言,Token有效期不應超過你需要使用它的時間。
無論何時使用者想要通路受保護的路由或者資源的時候,使用者代理(通常是浏覽器)都應該帶上JWT。通常JWT放在Authorization header中,用bearer schema。
header通常為這種形式:
Authorization: Bearer
伺服器上的受保護的路由将會檢查Authorization header中的JWT是否有效。如果有效,則使用者可以通路受保護的資源。如果JWT包含着足夠多的必要的求取資料,那麼就可以減少服務端去資料庫查詢的很多操作。
如果token是在授權頭(Authorization header)中發送的,那麼跨源資源共享(CORS)将不會成為問題,因為它不使用cookie。
五、 基于Token的身份認證 與 基于伺服器的身份認證
1.基于伺服器的身份認證
HTTP協定是無狀态的。也就是說,我第一次登陸時已經認證了一個使用者,但是當我第二次登陸發送請求的時候,伺服器依然不知道我是誰,我必須再次認證。
傳統的做法是将已經認證過的使用者資訊存儲在伺服器上,比如Session。使用者下次請求的時候帶着Session ID,然後伺服器檢查Session 确認使用者是否認證過。
這種基于伺服器的身份認證方式存在一些問題:
-
Sessions :
每次使用者認證通過以後,伺服器需要建立一條記錄儲存使用者資訊,通常是在記憶體中,随着認證通過的使用者越來越多,伺服器的在這裡的開銷就會越來越大。
- Scalability : 由于Session是在記憶體中的,這就帶來一些擴充性的問題。
-
CORS :
當我們想要擴充我們的應用,讓我們的資料被多個移動裝置使用時,我們必須考慮跨資源共享問題。當使用AJAX調用從另一個域名下擷取資源時,我們可能會遇到禁止請求的問題。
- CSRF : 使用者很容易受到CSRF攻擊。
2.JWT與Session的異同
- JWT和Session都是存儲使用者資訊的載體,但是Session是存儲在伺服器端的,而JWT是存儲在用戶端的。
- 方式存儲使用者資訊的最大問題在于要占用大量伺服器記憶體,增加伺服器的開銷;而JWT方式将使用者狀态分散到了用戶端中,可以明顯減輕服務端的記憶體壓力。
- Session的狀态存儲在伺服器端,用戶端隻有session id;而Token的狀态存儲在用戶端。
淺談JWT
3.基于Token的身份認證
基于Token的身份認證是無狀态的,伺服器中不會存儲任何使用者資訊。
沒有會話資訊意味着應用程式可以根據需要擴充和添加更多的機器,而不必擔心使用者登入的位置。
這一實作的主要流程如下:
- 使用者攜帶使用者名和密碼請求通路
- 伺服器校驗使用者憑據
- 應用提供一個token給用戶端
- 用戶端存儲token,并且在随後的每一次請求中都帶着它
- 伺服器校驗token并傳回資料
注意:
- 每一次請求都需要token
- Token應該放在請求header中
- 我們還需要将伺服器設定為接受來自所有域的請求,用Access-Control-Allow-Origin: *
4.Token的優勢
- 無狀态和可擴充性:Tokens存儲在用戶端。完全無狀态,可擴充。我們的負載均衡器可以将使用者傳遞到任意伺服器,因為在任何地方都沒有狀态或會話資訊。
- 安全:Token并不是Cookie,每次請求的時候Token都會被發送。而且,由于沒有Cookie被發送,還有助于防止CSRF攻擊。即使在你的實作中将token存儲到用戶端的Cookie中,這個Cookie也隻是一種存儲機制,而非身份認證機制。沒有基于會話的資訊可以操作,因為我們沒有會話。
還有一點,token在一段時間以後會過期,這個時候使用者需要重新登入。這有有利于安全性。還有一個概念叫token撤銷,它允許我們根據相同的授權許可使特定的token甚至一組token無效。
5. JWT與OAuth的差別
- OAuth2是一種授權架構 ,JWT是一種認證協定
- 無論使用哪種方式切記用HTTPS來保證資料的安全性
- OAuth2用在使用第三方賬号登入的情況(比如使用weibo, qq, github登入某個app),而JWT是用在前後端分離, 需要簡單的對背景API進行保護時使用。