一文讀懂 JWT

image.png

什麼是 JWT

JWT 全稱爲 JSON Web Token 是一種在跨域時驗證用戶的一種措施。

javascript

JWT 與 傳統 COOKIE SESSION 的區別是什麼?

首先咱們來回想一下傳統 cookie session 的驗證流程
html

  1. 客戶端登錄帳號
  2. 服務端接受到用戶信息,驗證帳號密碼,簽發一個 sessionId,以 cookie 的方式的返回給客戶端存儲
  3. 每當下次請求的時候,客戶端就會攜帶上同域名的 cookie,裏面就有 sessionId,以此標識用戶身份。


這樣會有一個問題,若是 網站A 和 網站B 都是同一家公司。如今要求,網站A 登錄了,網站B 也自動登錄,請問怎麼實現?

一種是 Session 持久化,寫入數據庫或者其餘持久層(好比 redis),各類服務收到請求後,都向持久層請求數據,這種模式架構清晰,可是工程量大,且萬一持久層失效,單點登錄就會失效。

一種則是服務器直接放棄存儲 session 數據了,直接將信息存在客戶端。**JWT **就是這種方案的一個表明

java

JWT 原理

JWT 的原理是,服務器認證之後,生成一個 JSON 對象發送給客戶端,大概長這樣。
node

{
  "name": 'cjfff', 
  "role": "admin",
  "ita": "認證時間"
}
複製代碼


日後在通訊過程當中,每次客戶端請求都帶上,以識別身份。

可是爲了防止數據被擅改,會加入簽名信息(Signature)。

git

JWT 的數據結構

組成部分

實際的 JWT 是圖示這個樣子。

github

image.png

這裏對數據進行了手動回車換行,方便你們下面複製對比。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiY2pmZmZmIiwiaWF0IjoxNTE2MjM5MDIyfQ
.D7OUQ7tygm9PDjXeroA0w3dV4G0Swcbju0jHkS7Hqww
複製代碼


能夠看到分爲了三個部分web

  1. header 紅色部分
  2. payload 紫色部分
  3. signature 藍色部分

每一個部分的信息都是怎麼來的?

這裏先來個幫助函數
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(''));
  }
};
複製代碼
  1. header 記錄着加密算法信息

大概以下,裏面記錄着 type,alg 就是加密算法, 能夠看到,加密後是與開頭數據結構中的 header(第一部分是相同的).
算法

Base64.encode(JSON.stringify({
  "alg": "HS256",
  "typ": "JWT"
})) === 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' // true
複製代碼

  1. payload 用戶信息以及簽發時間


能夠看到 payload 信息也是產出一致的。
數據庫

Base64.encode(JSON.stringify({
  "role": "admin",
  "name": "cjffff",
  "iat": 1516239022
})) === 'eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiY2pmZmZmIiwiaWF0IjoxNTE2MjM5MDIyfQ'
複製代碼

  1. Signature 簽名


簽名的生成規則以下,這裏就不作測試了

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)
複製代碼


他們三個部分以 . 組合後就是 JWT 總體數據結構。

JWT 安全嗎?

JWT 只是爲了解決用戶會話的問題,大白話就是識別用戶身份。

JWT 自己並無進行加密的行爲,Signature(簽名) 也只是爲了別人擅改數據而已,若是數據被抓包,payload(jwt第二部份內容)中若是攜帶用戶敏感信息的話,第三方使用 base64 解密便可得到數據,因此爲了安全性而言請使用 https 代替 http。
**
另外就是應該防止加密用的 **secret **泄漏。

安全總結:

  1. 使用 https 代替 http
  2. 防止 secret 泄漏
  3. 能夠對 JWT 進行二次加密(須要額外消耗)

JWT 如何過時?

**JWT **在簽發的時候會爲 **payload **加上一個 iat(issued at) 簽發時間。

而後客戶端下次發送帶上發送給服務端的時候會根據服務端的過時策略進行驗證

好比,服務端設置的過時時間是 10h

  1. 服務端接收到 jwt ,解密後得到簽發時間
  2. 若是簽發時間 + 10h < 當前時間就是過時了


另外就是,若是用戶數據被擅改,此時 JWT 應該是屬於過時的,但因爲 JWT 的機制問題,token 簽發後並無相關的廢棄策略,只能使用額外的邏輯去對過時的 JWT 進行過時操做,好比將過時的 JWT 維護在 黑名單列表中。

JWT 如何使用?


客戶端收到服務端返回的 JWT 後,能夠存儲在 COOKIE 中,也能夠存儲在 localStorage 中。

當每次發送請求的時候, 在 headers 加上 Authorization 字段,內容爲 Bearer ${jwt} 便可

而後服務端會用上述接收到的信息,拿到 header + payload 爲輸入數據,進行上面算法生成 Signature 再和 客戶端接收到的 Signature 進行對比,一致的話就完成了驗證。

JWT Koa2 demo

koa-jwt-demo 地址

參考

  1. 阮一峯 JWT 入門
  2. JWT 官網

## 延伸閱讀
  1. jsonwebtoken 源碼 裏面就是根據上述規則去寫的邏輯,感興趣的能夠看看
相關文章
相關標籤/搜索