JSON Web Token, 或JWT (jot) 簡單來說, 是一種傳送驗證授權的標準。 為什麼我們需要JWT? 從前我們在驗證使用者身份後,可能會將使用者資訊存在於session當中,這種做法有幾種缺點:
- 造成Server記憶體負擔
- 如果需將Application掛載於多台Server上,必須要同步所有的Server的session
- 無法處跨平台授權問題
於是,JWT誕生了。因為Http 的請求是無狀態的(stateless)因此我們必須將sessiont儲存在Server Side. 我們利用JWT的技術標準,由Server Side產生一組token給予Client Side, 再由Client Side保存好,並在每一次Request將token帶入。 這間接解決了cookie的缺點,不易被竄改。
談到這我們就可以來說明token的優點:
安全性
如上述所說明, 除了token沒機會被修改以外, 我們也可以要求token的時效性來提高安全性。
擴充性
我們可以利用token來分享權限給予第三方使用者
解決跨域問題
傳統cookie在登入的時候必須在所有domain寫入,但token只要實作相同的驗證機制即可
說了這麼多,我們還是要來談論,如何實作JWT機制
JWT主要分為三個部分:
- header (標頭)
- payload(訊息內容)
- signature(簽章)
最終組成一個Token:
{header}.{payload}.{signature}
Header的內容為 JSON物件:
{ "alg": "HS256", "typ": "JWT" }
Header 主要是說明JWT將用何種演算法建立。
Payload的內容也是JSON物件:
{ "sub": "1234567890", "name": "John Doe", "admin": true }
Payload主要承載使用者需要的資訊,官方的HandBook有說明沒有硬性規定哪些必要屬性。
但仍舊可以歸納出幾個特別的要求:
- iss: issuer,帶有機密資料的字串或是URI,可明確指出是由誰發行此JWT
- sub: subject,帶有機密資料的字串或是URI,說明JWT的內容
- aud: audience,帶有機密資料的字串或是URI或是陣列,指出JWT的受眾
- exp: expiration,代表特定時間的數字,依循POSIX定義的"seconds since epoch"格式,明確指出JWT的過期時間
- nbf: not before,與exp相反,依循POSIX定義的"seconds since epoch"格式,明確指出JWT的的開始生效日期
- iat: issue at (time),與exp和nbf格式相同,為JWT的發行時間
- jti: JWT id,識別此JWT的唯一字串
JSON Web Signatures 大概是JWT 最重要的特性之一,先前說過JWT是由Header.Payload.Signature組成,
大概會是類似下面的範例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. (header) eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.(payload) TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ(signature)
依據JWT 規範,有數種簽章演算法可用,因此會有多種不同的解譯。 JWT要求單一演算法以支援相同實作
- HMAC using SHA-256,在JWT中稱作HS256
- RSASSA PKCS1 v1.5 using SHA-256,在JWT稱作RS256
- ECDSA using P-256 and SHA-256,在JWT稱作ES256
JWA為JSON Web Algorithms的縮寫,還有許多演算法就不在此詳列。
HMAC-based的簽章演算法範例如下:
const encodedHeader = base64(utf8(JSON.stringify(header))); const encodedPayload = base64(utf8(JSON.stringify(payload))); const signature = base64(hmac(`${encodedHeader}.${encodedPayload}`,secret, sha256)); const jwt = `${encodedHeader}.${encodedPayload}.${signature}`;