博客 / 詳情

返回

為什麼JWT要結合Redis使用

JWT和Redis結合使用的深入探討

JWT (JSON Web Token) 是一種緊湊、自我包含的方式,用於在各方之間安全地傳輸信息。JWT 基於標準 RFC 7519,其中包含了以 JSON 格式存儲的信息。其主要優勢在於無狀態性,能夠減少服務器存儲壓力。JWT 的信息通過數字簽名加密,可以由持有者驗證信息的完整性。然而,JWT 的無狀態性在某些情況下也可能帶來一定的安全和性能問題,這就是為什麼在開發實踐中,經常將 Redis 引入到 JWT 的實現中。

JWT的無狀態性問題

JWT 的設計初衷是無狀態,這意味着當服務器簽發一個 JWT 後,服務器端不會維護該 JWT 的狀態。雖然這種設計減輕了服務器的負擔,但在一些特殊場景下可能會帶來以下幾個問題:

問題 1:無法撤銷已簽發的 JWT

當用户登出或 JWT 被盜用時,JWT 並不會在服務器端被撤銷。也就是説,儘管用户希望登出或重新生成令牌,攻擊者仍然可以使用原始 JWT 直到它過期。例如:

  1. 用户登出:通常,JWT 不會因為用户的登出而失效,攻擊者依然能夠使用盜取的 JWT 進行操作。
  2. JWT 被盜:JWT 一旦被盜,攻擊者可以在其有效期內持續使用。

解決方法: 我們可以使用 Redis 來記錄 JWT 的狀態。每次請求到達服務器時,除了驗證 JWT 的簽名外,還要檢查該 JWT 是否在 Redis 中被標記為無效。這樣,攻擊者即使竊取了 JWT 也無法繼續使用。

問題 2:無法動態修改權限

JWT 中可能包含用户的角色、權限等信息。如果用户的權限發生了改變(例如被授予管理員權限),但 JWT 在過期前仍然使用舊的權限信息,這可能導致權限的濫用或功能限制。

解決方法: 可以將用户的權限信息存儲在 Redis 中,每次請求時通過 Redis 校驗最新的權限信息,而不依賴 JWT 本身的內容。


Redis的作用

Redis 是一個開源的內存數據庫,通常用作緩存或數據存儲系統。結合 JWT,Redis 可以彌補 JWT 的無狀態性帶來的不足。下面詳細分析 Redis 如何提升 JWT 的安全性和性能。

1. 管理 JWT 的有效性

將 JWT 的 ID(如 jti,JWT ID)存儲在 Redis 中,標記該 JWT 的有效期與狀態。當 JWT 被簽發時,將其 jti 與過期時間寫入 Redis,登出或其他特殊操作時,可通過修改 Redis 中的記錄使該 JWT 無效。這樣,無論 JWT 是否在其有效期內,只要服務器發現它在 Redis 中被標記為無效,就會拒絕該 JWT 的請求。

流程圖:JWT 有效性驗證和撤銷流程
st=>start: 用户請求
jwtv=>condition: 驗證JWT簽名?
valid=>condition: JWT在Redis中有效?
deny=>operation: 拒絕請求
allow=>operation: 允許訪問
end=>end: 完成

st->jwtv(yes)->valid(yes)->allow->end
jwtv(no)->deny->end
valid(no)->deny

2. 存儲用户的狀態和權限信息

JWT 本質上是自我包含的,這意味着它在創建時將包含所有用户信息。如果需要頻繁讀取某些用户狀態或權限信息(例如,用户角色),頻繁地解碼 JWT 或查找數據庫都會影響系統性能。而 Redis 可以緩存這些信息,在用户登錄時將角色和權限等信息存儲在 Redis 中,後續請求可以直接從 Redis 中讀取,減少數據庫的壓力。

用户權限緩存邏輯示例
  • 登錄時: 將用户的角色和權限信息緩存到 Redis。
  • 請求時: 檢查 Redis 中的權限信息,避免每次解碼 JWT 或訪問數據庫。

Redis的優勢

  • 高效性:Redis 是內存數據庫,讀取速度極快,適合存儲用户狀態、權限等經常訪問的數據。
  • 可擴展性:Redis 支持集羣,能輕鬆處理大規模併發訪問。
  • 易於使用:通過簡單的鍵值對存儲,Redis 可以方便地與 JWT 結合,保持用户的狀態信息。

JWT 與 Redis 結合的最佳實踐

1. 存儲 JWT 的唯一標識符

JWT 通常會包含一個 jti(JWT ID),這是每個 JWT 的唯一標識符。當 JWT 被創建時,將其 jti 和過期時間存儲在 Redis 中。Redis 的 TTL(生存時間)機制會確保記錄會自動過期,無需手動管理。

示例:存儲 jti 在 Redis 中
# 假設有一個 Redis 連接對象 redis_conn
jti = jwt_payload['jti']
expiration_time = jwt_payload['exp'] - current_time

# 存儲在 Redis 中
redis_conn.set(jti, "valid", ex=expiration_time)

解釋:

  • jti 是 JWT 的唯一標識符。
  • expiration_time 表示該 JWT 的過期時間。
  • redis_conn.set() 將 jti 存儲在 Redis 中,並設置其過期時間。

2. 在每次請求中驗證 JWT 狀態

每當服務器收到帶有 JWT 的請求時,不僅要驗證 JWT 的簽名,還要查詢 Redis 中該 jti 的狀態。如果在 Redis 中找不到該 jti 或其狀態為“無效”,則拒絕請求。

示例:驗證 JWT 狀態
jti = jwt_payload['jti']
jti_status = redis_conn.get(jti)

if jti_status is None:
    # JWT 在 Redis 中不存在,拒絕訪問
    raise InvalidTokenError("Token has been revoked or expired")

3. 用户登出時使 JWT 失效

當用户登出時,將該用户的 JWT 在 Redis 中標記為無效。即使 JWT 本身的有效期未到,由於 Redis 中的記錄已更新,該 JWT 也會被視為無效。

示例:登出時撤銷 JWT
# 將 JWT 標記為無效
redis_conn.set(jti, "revoked")

JWT 和 Redis 結合的優缺點對比表

特性 JWT JWT + Redis
狀態管理 無狀態 有狀態,通過 Redis 管理
撤銷機制 無法撤銷 可以通過 Redis 使 JWT 失效
性能 高,所有信息保存在 JWT 內部 略有降低,需要訪問 Redis
安全性 安全性較弱,JWT 被盜用後無法阻止 安全性增強,可在 Redis 中撤銷或修改 JWT
用户狀態信息獲取 需要解碼 JWT 或訪問數據庫 直接從 Redis 獲取,性能更優

總結

JWT 是一種無狀態的認證方式,適合用於分佈式系統,能夠減輕服務器的壓力,但由於其無狀態性,可能會帶來安全和管理上的問題。而通過將 RedisJWT 結合使用,可以彌補 JWT 的不足,增加系統的安全性和靈活性。Redis 不僅能夠存儲和管理 JWT 的狀態,還能緩存用户的權限和狀態信息,大幅度提高系統性能,尤其是在高併發的場景下。

重要點總結:

  1. JWT 是無狀態的,無法撤銷或修改,結合 Redis 可以有效解決此問題。
  2. 使用 Redis 可以提高系統性能,減少數據庫壓力,增強系統的擴展性。
  3. Redis 可以幫助實現 JWT 的實時管理,例如用户登出後撤銷 JWT 或動態修改用户權限。

結合 JWT 與 Redis,開發人員可以構建更加安全、靈活、高效的分佈式系統,確保數據傳輸的可靠性和系統的性能。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.