天天看點

Python 生成 JWT(json web token) 及 解析方式

一.關于 jwt 的原理及概念可以自行在網絡上搜尋了解一下,這裡推薦一篇寫的比較好的部落格

  深入了解Json Web Token之概念篇

  另附 JWT 的官方文檔: https://jwt.io/introduction/

二.python 對于 jwt 的實作, 目前已經存在了一些第三方的庫, 相信學習過 python 的程式猿都知道 itsdangerous 這個庫了, 它的底層原理就是基于 jwt 進行實作的

  這裡需要進行提醒的是:

  itsdangerous (使用固定密鑰/字元串進行加密, jwt 有多種加密方式, 這隻是其中一種, 建議先去了解一下)所生成的 token 仍然是可以被破譯進而看到 jwt 的 payload(有效負載) 裡的資料, 隻不過因為破譯者并不知道加密的密鑰, 也就無法對資料進行篡改, 是以如果是私密的資料, 就不應該使用 jwt 進行傳遞, 如 賬号的密碼, 以防止洩露. 如果需要傳遞私密資料, 解決辦法是,對 payload 的資料進行加密,進而杜絕非法破譯者看到 payload 内的任何資訊,但是目前加密payload的操作不是很普及,在不加密 payload 的前提下, jwt 比較适合進行非受信任端的身份驗證, 此時即使接收方破譯了 token, 看到了 payload 的資料, 也不會造成太大的影響, 因為資料是無法被篡改的(當接收方将 token 值傳回給伺服器後, 需要使用相同的密鑰進行解密, 是以伺服器的密鑰一定要保管好), 隻要接收方将 token 原封不動的傳回給伺服器, 那麼伺服器就可以根據 token 值的内容來确認接收方身份的合法性,而不需要關心接收方是否看到過 payload 的内容.

  簡而言之, 除非額外對 payload 加密過, 否則就不要在 jwt 中傳遞不可被第三方獲知的私密資料

三. python實作生成 json web token

  環境: python3.6.7

  依賴包: jwt, time

  1)JWT 的簽名算法有三種。

    1.對稱加密HMAC【哈希消息驗證碼】  HS256/HS384/HS512   

      這種加密方式沒有公鑰,私鑰之分, 也就是隻有一個密鑰, 這種加密方式适用于: 伺服器将生成的jwt發送給接收方, 接收方将其傳回給伺服器, 伺服器解析 jwt, 完成身份驗證.

     2.非對稱加密RSASSA【RSA簽名算法】RS256/RS384/RS512

     3.ECDSA【橢圓曲線資料簽名算法】 ES256/ES384/ES512

  2).對稱加密HMAC 生成 jwt

import time
import jwt

# payload
token_dict = {
    \'iat\': time.time(),  # 時間戳
   \'name\': \'lowman\'  # 自定義的參數
}      
"""payload 中一些固定參數名稱的意義, 同時可以在payload中自定義參數"""
# iss  【issuer】釋出者的url位址
# sub 【subject】該JWT所面向的使用者,用于處理特定應用,不是常用的字段
# aud 【audience】接受者的url位址
# exp 【expiration】 該jwt銷毀的時間;unix時間戳
# nbf  【not before】 該jwt的使用時間不能早于該時間;unix時間戳
# iat   【issued at】 該jwt的釋出時間;unix 時間戳
# jti    【JWT ID】 該jwt的唯一ID編号
# headers
headers = {
    \'alg\': "HS256",  # 聲明所使用的算法
}

"""headers 中一些固定參數名稱的意義"""
# jku: 發送JWK的位址;最好用HTTPS來傳輸
# jwk: 就是之前說的JWK
# kid: jwk的ID編号
# x5u: 指向一組X509公共證書的URL
# x5c: X509證書鍊
# x5t:X509證書的SHA-1指紋
# x5t#S256: X509證書的SHA-256指紋
# typ: 在原本未加密的JWT的基礎上增加了 JOSE 和 JOSE+ JSON。JOSE序列化後文會說及。适用于JOSE标頭的對象與此JWT混合的情況。
# crit: 字元串數組,包含聲明的名稱,用作實作定義的擴充,必須由 this->JWT的解析器處理。不常見。
# 調用jwt庫,生成json web token
jwt_token = jwt.encode(token_dict,  # payload, 有效載體 
                       "zhananbudanchou1234678",  # 進行加密簽名的密鑰
                       algorithm="HS256",  # 指明簽名算法方式, 預設也是HS256
                       headers=headers  # json web token 資料結構包含兩部分, payload(有效載體), headers(标頭)
                       ).decode(\'ascii\')  # python3 編碼後得到 bytes, 再進行解碼(指明解碼的格式), 得到一個str

print(jwt_token)

# 個人測試生成結果如下: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6Ijk1MjcifQ.eyJpYXQiOjE1NTkyNzY5NDEuNDIwODgzNywibmFtZSI6Imxvd21hbiJ9.GyQhOJK8FKD_Gd-ggSEDPPP1Avmz3M5NDVnmfOfrEIY      

  3) 使用 python 對 jwt 進行解析

import jwt      
# 将上面生成的 jwt 進行解析認證

jwt_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6Ijk1MjcifQ.eyJpYXQiOjE1NTkyNzY5NDEuNDIwODgzNywibmFtZSI6Imxvd21hbiJ9.GyQhOJK8FKD_Gd-ggSEDPPP1Avmz3M5NDVnmfOfrEIY"

data = None
try:
  #           需要解析的 jwt        密鑰                使用和加密時相同的算法
  data = jwt.decode(token, "zhananbudanchou1234678", algorithms=[\'HS256\'])
except Exception as e:
  # 如果 jwt 被篡改過; 或者算法不正确; 如果設定有效時間, 過了有效期; 或者密鑰不相同; 都會抛出相應的異常
  print(e)

# 解析出來的就是 payload 内的資料
print(data)

# 輸出: {\'iat\': 1559276941.4208837, \'name\': \'lowman\'}      

  

  4)如果是使用私鑰公鑰進行加密解密的方式(由請求方使用私鑰進行加密生成 jwt, 接收方使用公鑰解密), 隻需要将相應參數更換成私鑰(将私鑰證書讀取出來, 指派給相應參數即可), 并使用雙方約定好的的簽名算法

  5)  python 對于 jwt 的實作, 已經有了 itsdangerous 這個庫做了很好的支撐, 使用起來還是很友善的, 大家可以自行去了解一下.

    itsdangerous 官方文檔: https://itsdangerous.readthedocs.io/en/1.1.x/

Python 生成 JWT(json web token) 及 解析方式