1. 程式人生 > >認證方案之初步認識JWT

認證方案之初步認識JWT

前言:

  現在越來越多的專案或多或少會用到JWT,為什麼會出現使用JWT這樣的場景的呢?

  假設現在有一個APP,後臺是分散式系統。APP的首頁模組部署在上海機房的伺服器上,子頁面模組部署在深圳機房的伺服器上。此時你從首頁登入了該APP,然後跳轉到子頁面模組。session在兩個機房之間不能同步,使用者是否需要重新登入?

傳統的方式(cookie+session)需要重新登入,使用者體驗不好。session共享(在多臺物理機之間傳輸和複製session)方式對網路IO的壓力大,延遲太長,使用者體驗也不好。

  說到這大家可能會想到,用伺服器的session_id儲存到cookies中也能做到,為什麼非要用token呢?網上有許多文章來比較token和session的優缺點,其實,開發web應用的話用哪種都行。但如果是開發api介面,前後端分離,最好使用token,為什麼這麼說呢,因為session+cookies是基於web的。但是針對 api介面,可能會考慮到移動端,app是沒有cookies和session的。

  Session方式儲存使用者資訊的最大問題在於要佔用大量伺服器記憶體,增加伺服器的開銷。

  而JWT方式將使用者狀態分散到了客戶端中,可以明顯減輕服務端的記憶體壓力。Session的狀態是儲存在伺服器端,客戶端只有session id;而Token的狀態是儲存在客戶端

原理:

JSON Web Token(縮寫 JWT)

    JWT 的原理是,伺服器認證以後,生成一個 JSON 物件,發回給使用者,以後,使用者與服務端通訊的時候,都要發回這個 JSON 物件。

  伺服器完全只靠這個物件認定使用者身份。為了防止使用者篡改資料,伺服器在生成這個物件的時候,會加上簽名。

  伺服器就不儲存任何 session 資料了,也就是說,伺服器變成無狀態了,從而比較容易實現擴充套件。

組合:

 JWT 的三個部分依次是:Header(頭部)、Payload(負載)、Signature(簽名)

寫成一行,就是下面的樣子。

Header.Payload.Signature

 一、Header

header典型的由兩部分組成:token的型別(“JWT”)和演算法名稱(比如:HMAC SHA256或者RSA等等)

        {
          "alg": "HS256", //alg屬性表示簽名的演算法(algorithm),預設是 HMAC SHA256(寫成 HS256)
          "typ": "JWT"   //typ屬性表示這個令牌(token)的型別(type)
        }

然後用Base64對這個JSON編碼就得到JWT的第一部分

二、Payload

JWT的第二部分是payload,它包含宣告(要求)。宣告是關於實體(通常是使用者)和其他資料的宣告

JWT 規定了7個官方欄位

  • iss (issuer):簽發人
  • exp (expiration time):過期時間
  • sub (subject):主題
  • aud (audience):受眾
  • nbf (Not Before):生效時間
  • iat (Issued At):簽發時間
  • jti (JWT ID):編號

除了官方欄位,你還可以在這個部分定義私有欄位,下面就是一個例子

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
注意,不要在JWT的payload或header中放置敏感資訊,除非它們是加密的

三、Signature

Signature 部分是對前兩部分的簽名,防止資料篡改。簽名是用於驗證訊息在傳遞過程中有沒有被更改,並且,對於使用私鑰簽名的token,它還可以驗證JWT的傳送方是否為它所稱的傳送方。

為了得到簽名部分,你必須有編碼過的header、編碼過的payload、一個祕鑰,簽名演算法是header中指定的那個,然對它們簽名即可。按照下面的公式產生簽名。

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

算出簽名以後,把 Header、Payload、Signature 三個部分拼成一個字串,每個部分之間用"點"(.)分隔,就可以返回給使用者。

 

開始:

 一、客戶端收到伺服器返回的 JWT,可以儲存在 Cookie 裡面,也可以儲存在 localStorage。

此後,客戶端每次與伺服器通訊,都要帶上這個 JWT。你可以把它放在 Cookie 裡面自動傳送,但是這樣不能跨域,所以更好的做法是放在 HTTP 請求的頭資訊Authorization欄位裡面。

Authorization: Bearer <token>

二、JWT 就放在 POST 請求的資料體裡面,那麼跨源資源共享(CORS)將不會成為問題,因為它不使用cookie

1.應用(或者客戶端)想授權伺服器請求授權。例如,如果用授權碼流程的話,就是/oauth/authorize

2.當授權被許可以後,授權伺服器返回一個access token給應用

3.應用使用access token訪問受保護的資源(比如:API)

特點:

1.JWT 預設是不加密,但也是可以加密的。生成原始 Token 以後,可以用金鑰再加密一次。

2.JWT 不加密的情況下,不能將祕密資料寫入 JWT。

3.JWT 的最大缺點是,由於伺服器不儲存 session 狀態,因此無法在使用過程中廢止某個 token,或者更改 token 的許可權。也就是說,一旦 JWT 簽發了,在到期之前就會始終有效,除非伺服器部署額外的邏輯。

4.JWT 本身包含了認證資訊,一旦洩露,任何人都可以獲得該令牌的所有許可權。為了減少盜用,JWT 的有效期應該設定得比較短。對於一些比較重要的許可權,使用時應該再次對使用者進行認證。

注意:

JWT 是 JSON 格式的被加密了的字串

JWT 的核心是金鑰,就是 JSON 資料。這是你關心的,並希望安全傳遞出去的資料。JWT 如何做到這一點,並使你信任它,就是加密簽名。

 

被篡改之後

 

 

總結:

參考官方文件:JSON Web Tokens

&n