https://www.qikegu.com/easy-understanding/892
JWT
基於token的用戶認證原理:讓用戶輸入賬號和密碼,認證通過后獲得一個token(令牌),在token有效期里用戶可以帶着token訪問特定資源。
開始token並沒有一個統一標准,大家都各自使用自己的方案。后來出現了JWT(Json Web Token)這個標准。
JWT本質上是一個對JSON對象加密后的字符串。當服務器認證用戶通過后,一個包含用戶信息的json對象被加密后返回給用戶,json對象:
{
"UserName": "老王",
"Role": "admin",
"Expire": "2019-01-10 20:10:00"
}
之后,用戶訪問服務器時,都要返回這個json對象。服務器只靠這個對象就可以識別用戶身份,不需要再去查數據庫。為了防止用戶篡改數據,服務器在生成對象時將添加一個簽名。
服務器不保存任何會話數據,也就是說,服務器變得無狀態,從而更容易擴展。
JWT的結構
典型的JWT由三個部分組成,每個部分由一個點(.)分隔。
- Header
- Payload
- Signature
header.payload.signature
Header
頭部包含所使用的簽名算法和令牌的類型(即JWT),這部分會被編碼為Base64URL格式。
{
"alg": "HS256",
"typ": "JWT"
}
Base64URL的格式:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Base64URL
Base64編碼后可能出現字符+和/,在URL中不能直接作為參數,Base64URL就是把字符+和/分別變成-和_。JWT有可能放在url中,所以要用Base64URL編碼。
Payload
Playload包含實際要傳輸的信息,附帶一些其他信息如過期時間、發行時間等。JWT指定了一些官方字段(claims)備用:
- iss: 簽發人
- exp: 過期時間
- iat: 簽發時間
- nbf: 生效時間
- jti: 編號
- sub: 主題
- aud: 受眾
除了官方字段,在這個部分還可以添加私有字段,例如:
{
"sub": "1234567890",
"name": "隔壁老王",
"iat": 1516239022
}
這部分也是Base64URL編碼的:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IumalOWjgeiAgeeOiyIsImlhdCI6MTUxNjIzOTAyMn0
Signature
Signature部分是對前兩部分的防篡改簽名。將Header和Payload用Base64URL編碼后,再用點(.)連接起來。然后使用簽名算法和密鑰對這個字符串進行簽名:
signature = hmac_sha256(base64encode(header) + '.' + base64encode(payload), 'MY_SUPER_SECRET_KEY')
這個密鑰(MY_SUPER_SECRET_KEY)只有服務器才知道,不能泄露給用戶。
簽名信息:
huj1R4oYsSxbIpecRwGcDBzqFkL9dXA88P2ouM5xhT8
組合在一起
3部分組合在一起,構成了完整的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IumalOWjgeiAgeeOiyIsImlhdCI6MTUxNjIzOTAyMn0.huj1R4oYsSxbIpecRwGcDBzqFkL9dXA88P2ouM5xhT8
JWT怎么用
瀏覽器接收到服務器發過來的jwt后,可以存儲在Cookie或localStorage中。
之后,瀏覽器每次與服務器通信時都會帶上JWT。可以將JWT放在Cookie中,會自動發送(不跨域),或將JWT放在HTTP請求頭的授權字段中。
Authorization: Bearer <token>
也可放在url中,或POST請求的數據體中。
注意
- JWT默認是不加密的,但也可以加密,不加密時不宜在jwt中存放敏感信息
- 不要泄露簽名密鑰(MY_SUPER_SECRET_KEY)
- jwt簽發后無法撤回,有效期不宜太長
- JWT泄露會被人冒用身份,為防止盜用,JWT應盡量使用https協議傳輸