JWT 全稱爲 JSON Web Token 是一種在跨域時驗證用戶的一種措施。
javascript
首先咱們來回想一下傳統 cookie session 的驗證流程
html
這樣會有一個問題,若是 網站A 和 網站B 都是同一家公司。如今要求,網站A 登錄了,網站B 也自動登錄,請問怎麼實現?
一種是 Session 持久化,寫入數據庫或者其餘持久層(好比 redis),各類服務收到請求後,都向持久層請求數據,這種模式架構清晰,可是工程量大,且萬一持久層失效,單點登錄就會失效。
一種則是服務器直接放棄存儲 session 數據了,直接將信息存在客戶端。**JWT **就是這種方案的一個表明
java
JWT 的原理是,服務器認證之後,生成一個 JSON 對象發送給客戶端,大概長這樣。
node
{
"name": 'cjfff',
"role": "admin",
"ita": "認證時間"
}
複製代碼
日後在通訊過程當中,每次客戶端請求都帶上,以識別身份。
可是爲了防止數據被擅改,會加入簽名信息(Signature)。
git
實際的 JWT 是圖示這個樣子。
github
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiY2pmZmZmIiwiaWF0IjoxNTE2MjM5MDIyfQ
.D7OUQ7tygm9PDjXeroA0w3dV4G0Swcbju0jHkS7Hqww
複製代碼
能夠看到分爲了三個部分web
這裏先來個幫助函數
redis
const Base64 = {
encode(str) {
// first we use encodeURIComponent to get percent-encoded UTF-8,
// then we convert the percent encodings into raw bytes which
// can be fed into btoa.
let repMap = {
'=': '',
'+': '-',
'/': '_'
}
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
function toSolidBytes(match, p1) {
return String.fromCharCode('0x' + p1);
})).replace(/(=|\+|\/)/g, (key) => repMap[key])
},
decode(str) {
// Going backwards: from bytestream, to percent-encoding, to original string.
return decodeURIComponent(atob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
};
複製代碼
大概以下,裏面記錄着 type,alg 就是加密算法, 能夠看到,加密後是與開頭數據結構中的 header(第一部分是相同的).
算法
Base64.encode(JSON.stringify({
"alg": "HS256",
"typ": "JWT"
})) === 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' // true
複製代碼
能夠看到 payload 信息也是產出一致的。
數據庫
Base64.encode(JSON.stringify({
"role": "admin",
"name": "cjffff",
"iat": 1516239022
})) === 'eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiY2pmZmZmIiwiaWF0IjoxNTE2MjM5MDIyfQ'
複製代碼
簽名的生成規則以下,這裏就不作測試了
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
複製代碼
JWT 只是爲了解決用戶會話的問題,大白話就是識別用戶身份。
JWT 自己並無進行加密的行爲,Signature(簽名) 也只是爲了別人擅改數據而已,若是數據被抓包,payload(jwt第二部份內容)中若是攜帶用戶敏感信息的話,第三方使用 base64 解密便可得到數據,因此爲了安全性而言請使用 https 代替 http。
**
另外就是應該防止加密用的 **secret **泄漏。
安全總結:
**JWT **在簽發的時候會爲 **payload **加上一個 iat(issued at) 簽發時間。
而後客戶端下次發送帶上發送給服務端的時候會根據服務端的過時策略進行驗證
好比,服務端設置的過時時間是 10h
另外就是,若是用戶數據被擅改,此時 JWT 應該是屬於過時的,但因爲 JWT 的機制問題,token 簽發後並無相關的廢棄策略,只能使用額外的邏輯去對過時的 JWT 進行過時操做,好比將過時的 JWT 維護在 黑名單列表中。
客戶端收到服務端返回的 JWT 後,能夠存儲在 COOKIE 中,也能夠存儲在 localStorage 中。
當每次發送請求的時候, 在 headers 加上 Authorization 字段,內容爲 Bearer ${jwt}
便可
而後服務端會用上述接收到的信息,拿到 header + payload 爲輸入數據,進行上面算法生成 Signature 再和 客戶端接收到的 Signature 進行對比,一致的話就完成了驗證。