JWT 身份驗證

JWT token驗證

一.背景

​ HTTP是一種無狀態協議,即服務器不保留與客戶端交互時的任何狀態。也就是說服務端根本不知道是誰在使用這個應用,無法存儲這個記錄

​ 我們日常開發中,經常遇到這樣的問題:在很多操作下都要保存當前登錄人的信息,需要驗證當前是否登錄了,當前用戶是否有相應的權限等等.

​ 此時cookie就誕生了.

二.傳統的身份驗證

​ 1、用戶向服務器發送用戶名和密碼。

​ 2、服務器驗證通過後,在當前會話(session)裏面保存相關數據,比如用戶角色、登錄時間等等。

​ 3、服務器向用戶返回一個 session_id,寫入用戶的 Cookie 中。

​ 4、用戶隨後的每一次請求,都會通過 Cookie,將 session_id 傳回服務器。

​ 5、服務器收到 session_id,找到前期保存的數據,由此得知用戶的身份。

上面說的就是 Session,我們需要在服務端把登錄的用戶放進 Session ,這些 Session 會存儲在內存中。

缺點:

​ 單機環境是肯定是沒有問題的,但是如果要做服務器集羣,或者跨域的服務導向架構,那麼session就被限制了,需要做session的數據共享,使每臺服務器都能讀取session

三.jwt token身份驗證

在這裏插入圖片描述
由於 cookie-session 這種模式存在一些小問題。就出現了 jwt。

服務器不保存 session 數據了,所有數據都保存在客戶端。每次請求都返回服務器。

JWT (JSON Web Token) 是目前最流行的跨域認證解決方案。

1.驗證流程

​ 1.用戶向服務器發送用戶名和密碼.

​ 2.服務器驗證通過後,生成一個令牌(token),裏面存着相關數據,比如用戶信息和權限等

​ 3.服務器向用戶返回這個令牌(token),需要用戶自己選擇某種方式保存起來,一般可以使用

​ localStroage,sessionStorage,Cookie等

​ 4.用戶隨後的每一次請求,需要將token通過請求頭攜帶到服務器.請求頭字段名由後端指定,一般叫Authorization

​ 5.服務器收到令牌(token),通過解析就能得到用戶的身份信息

2.jwt組成

Header(頭部),Payload(載荷),Signature(簽名)

在這裏插入圖片描述
​ 它是一個比較使用 Base64 編碼的字符串. 中間用點分隔開,下面是一串真實的 Token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImxlY2hhciIsIml
zQWRtaW4iOnRydWUsImlhdCI6MTU4NTY2NjkzNiwiZXhwIjoxNTg1NjY2OTQ2fQ.
xvHerZ9gljCxj_-uj5p7xW6Wn1fPknAyI827lvxQf0Q
2.1 Header(頭部)

​ Header 部分是一個 JSON 對象,描述 JWT 的元數據,通常是下面的樣子。

{
  "alg": "HS256", //alg 屬性表示簽名的算法。默認是 HMAC SHA256 (寫成 HS256)
  "typ": "JWT"    //typ 屬性表示令牌的類型。jwt 令牌統一寫成 jwt
}

​ 最後使用 base64UrlEncode 將其轉成字符串

2.2 PayLoad(載荷)

​ Payload 部分也是一個 JSON 對象,用來存放實際需要傳遞的數據

​ JWT 規定了7個官方字段,供選用

  • iss (issuer):簽發人

  • exp (expiration time):過期時間

  • sub (subject):主題

  • aud (audience):受衆

  • nbf (Not Before):生效時間

  • iat (Issued At):簽發時間

  • jti (JWT ID):編號

除了官方字段,我們一般也會把自己需要存的數據存在裏面,如用戶的信息:

{
  "id":1,
  "username":"lechar",
  "isAdmin":"true"
}

最後使用 base64UrlEncode 將其轉成字符串

2.3 Signature(簽名)

Signature 部分是對前兩部分的簽名,防止數據篡改

首先,需要指定一個密鑰(secret)。這個密鑰需要在服務端創建並存儲,不能泄露給用戶。然後,使用 Header 裏面指定的簽名算法(默認是 HMAC SHA256),按照下面的公式產生簽名。

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

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

3.jwt的特點

1、JWT 默認是不加密,但也是可以加密的。生成原始 Token 以後,可以用密鑰再加密一次。

2、JWT 不加密的情況下,不能將祕密數據寫入 JWT。

3、JWT 不僅可以用於認證,也可以用於交換信息。有效使用 JWT,可以降低服務器查詢數據庫的次數。

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

5、JWT 本身包含了認證信息,一旦泄露,任何人都可以獲得該令牌的所有權限。爲了減少盜用,JWT 的有效期應該設置得比較短。對於一些比較重要的權限,使用時應該再次對用戶進行認證。

6、爲了減少盜用,JWT 不應該使用 HTTP 協議明碼傳輸,要使用 HTTPS 協議傳輸。

四.NodeJS使用jwt

不同的後臺語言中有不同的包來處理jwt。Node中一般使用 jsonwebtoken 這個包

1.安裝 jsonwebtoken
$ npm install jsonwebtoken
2.使用
//引入jsonwebtoken
const jsonwebtoken = require('jsonwebtoken');

//定義jwt 中的 palyload(存儲我們需要存的數據)
const playload = {
    "username": "lechar",
    "isAdmin": true
}

//定義加密的密鑰(一般後臺定義,或者後臺生成一個密鑰
// 放在private.key文件中,我們不對外暴露)
const secret = "abcdefg";

/**
 * 調用 jsonwebtoken.sign(payload, secret, options?) 方法生成 token
 *    - payload 需要存放到 token 中的數據
 *    - secret  祕鑰
 *    - options 可選的一些配置項
 */
const token = jsonwebtoken.sign(playload, secret, {
    // 過期時間,以秒或描述時間跨度的字符串表示,比如 60, '2 days', '10h', '7d'
    expiresIn: 10
});

console.log(token);
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
//eyJ1c2VybmFtZSI6ImxlY2hhciIsImlzQWRtaW4iOnRydWUsImlhdCI6MTU4NTY2NjkzNiwiZXhwIjoxNTg1NjY2OTQ2fQ.
//xvHerZ9gljCxj_-uj5p7xW6Wn1fPknAyI827lvxQf0Q
3.驗證與解碼
/**
 * 調用 jsonwebtoken.verify(token, secret, callback) 驗證與解碼
 *    - token     需要解碼的令牌
 *    - secret    祕鑰
 *    - callback  回調函數
 *        - error 解碼失敗
 *        - data  解碼出來的數據
 */


jsonwebtoken.verify(token,secret,(error,data)=>{
    console.log(data);
});

//打印結果是:
{ 
  username: 'lechar',
  isAdmin: true,
  iat: 1585667292,//簽發時間
  exp: 1585667302 //過期時間
}
4.ajax傳遞token
 $.ajax({
      url: `http://localhost:3000/`,
      type: "post",
      data: {
        title: $("#form-title").val(),
        content: $("#form-content").val()
      },
      // 請求頭中需要添加,後端怎麼定義,就怎麼傳
      headers: {
        //我們token可以存cookie和localStroge都可以,哪裏存哪裏取
        Authorization: Cookies.get("token")
      },
      success: function(res) {
          console.log(res);
      }
    });

參考鏈接:

阮一峯大神的博客

語雀文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章