jwt原理與實現

JWT

JSON Web Tokens,是一種開發的行業標準 RFC 7519 ,用於安全的表示雙方之間的聲明。目前,jwt廣泛應用在系統的用戶認證方面,特別是現在前後端分離項目。

JWT認證流程

jwt認證流程
在項目開發中,一般會按照上圖所示的過程進行認證,即:用戶登錄成功之後,服務端給用戶瀏覽器返回一個token,以後用戶瀏覽器要攜帶token再去向服務端發送請求,服務端校驗token的合法性,合法則給用戶看數據,否則,返回一些錯誤信息。

傳統token方式和jwt在認證方面的差異化?

  • 傳統token方式

    用戶登錄成功後,服務端生成一個隨機token給用戶,並且在服務端(數據庫或緩存)中保存一份token,以後用戶再來訪問時需攜帶token,服務端接收到token之後,去數據庫或緩存中進行校驗token的是否超時、是否合法。

  • jwt方式

    用戶登錄成功後,服務端通過jwt生成一個隨機token給用戶(服務端無需保留token),以後用戶再來訪問時需攜帶token,服務端接收到token之後,通過jwt對token進行校驗是否超時、是否合法。

JWT創建token

原理

jwt的生成token格式如下,即:由.連接的三段字符串組成。

例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

生成規則如下:

第一段 - HEADER部分:固定包含算法和token類型,對此json進行base64url加密,得到token的第一段

{
  "alg": "HS256",
  "typ": "JWT"
}

第二段 - PAYLOAD部分:,包含一些數據,對此json進行base64url加密,得到token的第二段。

# 非敏感信息
{
  "sub": "1",# 用戶的唯一標識
  "name": "hui", # 用戶名
  "iat": 1516239022,  # 可以自定義
  "exp": datetime.datetime(2019, 12, 9, 12, 10, 10, 414935)  # token過期時間
}

第三段 - SIGNATURE部分:把前兩段的base密文通過.拼接起來,然後對其進行HS256加密,再然後對hs256密文進行base64url加密,最終得到token的第三段。

base64url(
    HMACSHA256(
      base64UrlEncode(header) + "." + base64UrlEncode(payload),
      your-256-bit-secret (祕鑰加鹽)
    )
)

最後將三段字符串通過 .拼接起來就生成了jwt的token。

注意:

  1. base64url加密是先做base64加密,然後再將 - 替代 + 及 _ 替代 /
  2. base64url加密可以反解密。
代碼實現

基於Python的pyjwt模塊

# 安裝 pip install pyjwt

import jwt
import datetime
from jwt import exceptions
 
SALT = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='
 
def generate_token():
    # 構造header
    headers = {
        'typ': 'jwt',
        'alg': 'HS256'
    }
    # 構造payload
    payload = {
        'user_id': 1, # 自定義用戶ID
        'username': 'hui', # 自定義用戶名
        'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=1) # 超時時間
    }
 
    result = jwt.encode(payload=payload, key=SALT, algorithm="HS256", headers=headers).decode('utf-8')
    return result


if __name__ == '__main__':
    token = generate_token()
    print(token)

JWT校驗token

一般在認證成功後,把jwt生成的token返回給用戶,以後用戶再次訪問時候需要攜帶token,此時jwt需要對token進行超時及合法性校驗。

獲取token之後,會按照以下步驟進行校驗:

  • 將token分割成 header_segment、payload_segment、crypto_segment 三部分

    jwt_token =
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6
    IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_
    adQssw5c"
    
    signing_input, crypto_segment = jwt_token.rsplit(b'.', 1)
    header_segment, payload_segment = signing_input.split(b'.', 1)
    
  • 對第一部分header_segment進行base64url解密,得到header

  • 對第二部分payload_segment進行base64url解密,得到payload

  • 對第三部分crypto_segment進行base64url解密,得到signature

  • 對第三部分signature部分數據進行合法性校驗
    1、拼接前兩段密文,即:signing_input
    2、從第一段明文中獲取加密算法,默認:HS256
    3、使用 算法+鹽 對signing_input 進行加密,將得到的結果和signature密文進行比較。

# pip install pyjwt
import jwt
import datetime
from jwt import exceptions
 
def decode_token(token):
    """
    根據token獲取payload
    :param token:
    :return:
    """
    try:
        # 從token中獲取payload【不校驗合法性】
        # unverified_payload = jwt.decode(token, None, False)
        # print(unverified_payload)
 
        # 從token中獲取payload【校驗合法性】
        verified_payload = jwt.decode(token, SALT, True)
        return verified_payload
    except exceptions.ExpiredSignatureError:
        print('token已失效')
    except jwt.DecodeError:
        print('token認證失敗')
    except jwt.InvalidTokenError:
        print('非法的token')
         
if __name__ == '__main__':
    token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU"
    payload = decode_token(token)

參考博客:https://www.cnblogs.com/wupeiqi/p/11854573.html

發佈了8 篇原創文章 · 獲贊 1 · 訪問量 554
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章