iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
佛心分享-SideProject30

吃出一個SideProject!系列 第 12 篇

Day 12:Auth Service-登入流程 與 JWT Token

  • 分享至 

  • xImage
  •  

昨天我們總算完成了基礎的註冊功能。

今天要來實作登入功能,因為使用到 JWT,本節會先介紹 JWT 的概念與特色,再以循序圖介紹各元件如何進行溝通。礙於篇幅,會把實作細節留在明天。

Token 儲存機制:JWT 與 SessionId

JWT (JSON Web Token) 與 SessionId 是兩種主流的 Token 機制,他們最大的差異在於「登入資訊的儲存位置」:

  • SessionId 是將使用者的登入資訊儲存在伺服器端。
  • JWT 是將使用者的登入資訊編碼後直接儲存在客戶端。

Token 存放位置的選擇最主要的考量之一是「伺服器是否有水平擴展的需求?」若有,則需要伺服器保持無狀態(Stateless)。這種情況下,多數系統會選擇以 JWT 進行實作,因為即便將 SessionId 存在資料庫,當用戶數量到達一定程度,資料庫也會遇上負載或儲存空間的困擾。以 JWT Token 實作減少了這種認證時對共享儲存的查詢負擔(因為後端不需儲存Token)。

除此之外,兩種做法也各有其他優缺點,整理如下:

SessionId 與 JWT 的優缺點

  • SessionId
    • 優點
      • 安全性較高: 使用者狀態由伺服器管理,可以隨時主動將特定使用者的 Session 設為無效 (例如:使用者變更密碼、被停權)。
      • 傳輸量較小: Session ID 通常只是一段簡短的字串。
    • 缺點
      • 伺服器負擔: 每個使用者連線都需要在伺服器上儲存一個 Session,當使用者數量龐大時,會對伺服器造成較大的記憶體壓力。
      • 擴展性問題: 在分散式系統或多伺服器環境下,需要處理 Session 同步的問題,否則使用者可能會因為請求被導向不同伺服器而需要重新登入。
  • JWT
    • 優點
      • 無狀態與可擴展性: 伺服器不需要儲存使用者的登入狀態,這使得系統可以輕易地進行水平擴展 ,適合微服務架構。
      • 跨裝置與跨網域: JWT 可以透過多種方式傳遞 (HTTP Header、URL 參數等),不受限於 Cookie,因此在行動應用 (APP) 或跨網域的單一登入 (SSO) 等場景中非常方便。
    • 缺點
      • 無法主動註銷: 一旦 JWT 被簽發,在它過期之前都會是有效的。如果 JWT 在中途被竊取,攻擊者就可以在過期前一直使用它。可透過縮短 JWT 的有效期限,並搭配 Refresh Token 機制來緩解此風險。
      • Payload 資訊洩漏風險: JWT 的 Payload 僅是 Base64 編碼,並非加密。任何人都可以解碼看到其中的內容。
      • Token 體積較大: 因為包含了使用者資訊和簽名,JWT 的長度通常比 SessionId 長,可能會增加每次請求的網路傳輸量。

鑒於本次架構是以微服務的概念進行拆分,當前登入機制主流的作法多以保持伺服器無狀態為原則,因此本次會以 JWT 進行登入 token 的實作,以下稍微介紹一下 JWT 的組成與注意事項。

JWT Token 的組成與安全原則

  • JWT組成

    JWT Token 本身自帶用戶資訊,其由Header、Payload、Signature組成:

    • Header:存放通用資訊,例如使用的演算法跟Token類型。
    • Payload:用戶資訊、權限資訊的聲明(Claims)。
    • Signature:Signature:透過將 Header 和 Payload 進行雜湊運算,再使用伺服器端的「密鑰」對其進行數位簽章。此簽名用於驗證 Token 的完整性與來源,防止內容被惡意竄改。

    下方是在 jwt.io 中預設的案例,可以看到右側為 Header 與 Payload,左側則為按照這些資訊組成的 JWT Token,Header與 Payload 資訊會以 Baes64 編碼轉換:

    https://ithelp.ithome.com.tw/upload/images/20250926/20178099vB9pcpfAQZ.png
    圖片來源:jwt.io

  • JWT Token 應注意的安全原則

    • 密鑰管理
      • 強密鑰 :長度至少 256 bit
      • 定期更換 :每 3-6 個月更換一次
      • 環境隔離 :開發/測試/正式環境使用不同的密鑰
    • Token 效期管理
      • 控管時效 :常見設定為 15-30 分鐘內有效
      • 使用 Refresh token :token 換 token,長期但可撤銷
    • 避免存放個人機敏資訊 :因為是編碼非加密,機敏資料不應存在 JWT Token 中,只含必要用戶資訊。

登入流程循序圖

循序圖各組件介紹

  • 用戶端 :發起登入請求。
  • AuthController :接收並處理 HTTP 請求。
  • AuthService :處理業務邏輯,例如註冊。
  • UserDetailsServiceImpl :從資料庫加載使用者資訊供 Spring Security 使用。
  • UserEntity :代表資料庫中的使用者資料,實作 UserDetails 介面。
  • SecurityConfig :配置 Spring Security 的安全策略。
  • JwtUtils 負責 JWT Token 的生成與驗證。
  • LoginRequest :用戶端傳來的帳號密碼(登入請求的 DTO)。
  • LoginResponse:回傳給用戶端的 JWT Token 和使用者資訊 (登入回應 DTO)。

https://ithelp.ithome.com.tw/upload/images/20250926/201780995nSTqNlEP7.png

循序圖步驟說明

  1. 客戶端發送登入請求 (POST /users/login),請求 Body 中包含 Email 和密碼。
  2. Controller 接收到請求,並將 Email 和密碼打包成一個 UsernamePasswordAuthenticationToken 物件。
  3. Controller 呼叫 AuthenticationManager 的 authenticate() 方法,將 Token 傳入,啟動 Spring Security 認證流程。
  4. AuthenticationManager 將任務委派給內部的 DaoAuthenticationProvider。
  5. Provider 呼叫我們實作的 UserDetailsServiceImpl 的 loadUserByUsername() 方法,去資料庫查找使用者。
  6. UserDetailsServiceImpl 透過 UserRepository 查詢資料庫,若找到使用者,則將 UserEntity 物件回傳。若找不到,則拋出 UsernameNotFoundException。
  7. Provider 收到 UserEntity 後,使用我們在 SecurityConfig 中定義的 PasswordEncoder,比對請求傳入的密碼雜湊後和資料庫中的密碼是否相符。
  8. 若密碼匹配成功:AuthenticationManager 會回傳一個完全認證過的 Authentication 物件給 Controller。
  9. 若密碼不匹配:AuthenticationManager 會拋出 BadCredentialsException。
  10. Controller 收到認證成功的 Authentication 物件後,呼叫 JwtUtils 來生成 JWT Token。
  11. Controller 將 JWT Token 和其他必要的使用者資訊,打包成 LoginResponse DTO 回傳給客戶端。

上一篇
Day11:Auth Service -Global Exception
下一篇
Day 13:Auth Service-實作登入功能 (1)
系列文
吃出一個SideProject! 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言