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 呼叫 AuthenticationManagerauthenticate() 方法,將 Token 傳入,啟動 Spring Security 認證流程。
  4. AuthenticationManager 將任務委派給內部的 DaoAuthenticationProvider
  5. Provider 呼叫我們實作的 UserDetailsServiceImplloadUserByUsername() 方法,去資料庫查找使用者。
  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!13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言