Java 學習筆記:JWT(JSON Web Token)是什麼?

Java 學習筆記:JWT(JSON Web Token)是什麼?

什麼是 JWT?

JWT全名為 JSON Web Token,是一種用於安全傳遞資訊的標準。

為什麼會需要 JWT?

假設今天我們有一個網站,使用者登入後想查看自己的個人資料。

初次登入時,流程非常簡單,只需要在 Client 端打 POST /login API,輸入帳號密碼,伺服器驗證成功後,使用者就成功進入系統了。

但有個問題:之後每一次 API Request,Server 要怎麼知道這是同一位使用者?

如果每次都重新輸入帳號密碼,不但效率差,也會造成很差的使用體驗。

因此,我們就會需要一種登入之後,可以證明自己身份的方法。


傳統 Session 驗證

早期的網站通常使用 Session。

使用者初次成功登入系統後,Server 建立 Session,並回傳 Cookie,

之後每一次請求:

Cookie:
SessionID=ABC123

Server 透過 Session ID 找到 ABC123 所指的使用者,就可以知道「這位使用者已經登入。」

這種方式就是傳統 MVC 網站最常見的做法。


但隨著前後端分離逐漸普及,如果仍然使用 Session,就會出現以下的問題:

  • 擴充性較差。
  • Server 必須保存所有使用者的 Session。
  • 多台 Server 時,需要共享 Session。

因此,REST API 更傾向採用 Stateless 的設計。

也就是 Server 不需要記住任何登入資訊。

JWT 就是用來解決這個問題的方案。

JWT 最常見的用途包括:

  • 使用者登入驗證
  • API 身份驗證
  • 微服務之間傳遞身份資訊

登入成功後,Server 不會保存 Session,而是產生一個 JWT 並回傳給 Client。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

之後每一次 Request,Client 只要帶著這個 Token 即可。

例如:

GET /profile

Authorization: Bearer eyJhbGc...

Server 驗證 Token 後,就知道是哪位使用者。


JWT 的內部構造

JWT 一共由三個部分組成:

Header.Payload.Signature

三個部分之間以 . 隔開。

以下我們有一段 JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqZXJlbXkiLCJyb2xlIjoiVVNFUiIsImV4cCI6MTc1MzYwMDAwMH0.xxxxxxxxxxxxxxxx

可以直接貼上到 JWT 官方的 Decoder,可以看到 decode 結果如下圖


Header

首先是 Header 的部分,Header 描述 JWT 的基本資訊

例如:

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

代表:

  • typ:JWT
  • alg:使用 HS256 演算法進行簽章

通常 Header 不需要自行修改。


Payload

接下來是 Payload,用來存放資料,也稱為 Claims。

例如:

{
    "sub":"jeremy",
    "role":"USER",
    "exp":1753600000
}

常見欄位包括:

欄位說明
sub使用者身份
role使用者權限
expToken 到期時間
iat發行時間

你也可以加入自己的資料。

不過,Payload 並沒有加密,只經過 Base64 編碼。

任何拿到 JWT 的人,都可以解碼查看 Payload,在實作時,不要把機敏資訊存進 Payload。


Signature

最後是 Signature,Signature 是 JWT 最重要的部分。

它可以確保兩件事:

  • Token 沒有被修改
  • Token 真的是 Server 發出的

裡面包含 Service 的 Secret Key,因此如果有人偷偷修改 Payload,如原本:

role = USER

改成:

role = ADMIN

由於攻擊者不知道 Server 的 Secret Key,因此無法重新產生正確的 Signature。

當 Server 驗證 Token 時就會失敗,回傳 401 Unauthorized。


JWT 驗證流程

簡單介紹完 JWT 的組成後,驗證流程可以以下步驟表示:

  1. Client 端發送登入請求給 Server
  2. Server 驗證帳號密碼
  3. 若成功,Server 就會建立並回傳 JWT 給 Client
  4. Client 保存 Token
    • 通常存在Memory、HttpOnly Cookie 或 Local Storage(需小心 XSS 攻擊)
  5. 每次呼叫 API 都附帶上 Token
  6. Server 收到 API Request,便會驗證 JWT

Java SpringBoot 實作

了解 JWT 的運作原理後,接著來看看在 Spring Boot 中是如何建立 JWT 的。

實務上,JWT 通常會封裝在一個 JwtService 中,當使用者成功登入、帳號密碼驗證完成後,便會呼叫 generateToken() 方法建立 JWT,再回傳給 Client。

以下是一個簡化版的範例:

public String generateToken(String username) {

return Jwts.builder()
.subject(username)
.claim("role", "USER")
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(secretKey)
.compact();
}
  • subject(username):設定 JWT 的主體,通常會存放使用者名稱或使用者 ID。
  • claim("role", "USER"):加入自訂資訊(Claim),例如角色或權限。
  • issuedAt():設定 Token 的發行時間。
  • expiration():設定 Token 的有效期限,此範例為 1 小時
  • signWith(secretKey):使用 Server 的 Secret Key 對 JWT 進行簽章,避免 Token 遭到竄改。
  • compact():將 Header、Payload 與 Signature 組合成最終的 JWT 字串。

如果登入的使用者是 jeremy

String token = generateToken("jeremy");

就會產生一段類似下面的 JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

接著,Server 會將這個 Token 回傳給 Client。之後每次呼叫 API 時,Client 只需要將 JWT 放在 HTTP Header 中即可:

GET /profile

Authorization: Bearer eyJhbGc...

Server 收到請求後,便會驗證 JWT 是否有效,例如檢查 Signature 是否正確、Token 是否已過期,以及解析出其中的使用者資訊。若驗證成功,就代表這次請求是由合法且已登入的使用者發送。

在實務上,Spring Boot 通常會搭配 Spring Security 使用,並將 JWT 的建立與驗證封裝在 JwtService 中。登入成功時由 JwtService 產生 Token;後續每次 API Request,則由 Spring Security 負責驗證 JWT,再決定是否允許存取受保護的資源。


JWT 的優點

JWT 能夠成為現代 API 身份驗證的主流方案,主要有以下幾個優點:

  • Stateless(無狀態):Server 不需要保存每位使用者的登入資訊。
  • 適合 REST API:每個 Request 都能獨立完成驗證。
  • 容易水平擴充:多台 Server 不需要同步 Session。
  • 適合微服務:不同服務可以共享同一個 Token。

JWT 的缺點

JWT 雖然方便,但也有一些限制:

  • 無法輕易讓 Token 提前失效。
  • Token 一旦外洩,在過期前都可能被使用。
  • Header 會比 Session Cookie 更長。
  • Secret Key 必須妥善保存。

因此,實務上通常會搭配短效 Access Token 和 Refresh Token 來降低 Token 外洩帶來的風險。

Access Token:有效時間較短(例如 15 分鐘),每次 API Request 都會攜帶。

Refresh Token:有效時間較長(例如 7 天),當 Access Token 過期時,可用來取得新的 Access Token,而不需要重新登入。


JWT 與 Session 比較

JWTSession
Server 不保存登入資訊Server 保存 Session
StatelessStateful
適合 REST API適合傳統 Web
易於水平擴充多台 Server 需共享 Session
常用於前後端分離的專案常見於 MVC 專案

結語

一開始會接觸到 JWT,也是因為在設計前後端分離的全端專案時,一直思考著什麼樣的驗證方式才最適合自己的系統。

剛開始,我也曾嘗試過較簡單的驗證方式,如 HTTP Basic Auth,希望能快速完成登入功能。然而,隨著系統加入更多 API,以及開始思考前後端分離、權限管理和後續的擴充性,才發現這些方式在實務上都有一定的限制。

深入了解後,我才開始接觸 JWT。它最大的特色,是能夠讓 Server 在無狀態的情況下驗證使用者身份的機制。也因為如此,它成為現代 REST API 和前後端分離架構中最常見的身份驗證方案之一。

發表留言