---
# System prepended metadata

title: JSON Web Token (JWT)
tags: [Authentication]

---

---
tags: Authentication
---
# JSON Web Token (JWT)
## 前言
HTTP Protocol 是無狀態(stateless)的，所以即使這位用戶在這一次的請求中傳遞了帳戶及密碼並通過了驗證，在下一次的請求當中，我們仍然不能識別出這位使用者，因為兩次的 HTTP 請求是沒有關聯的。為了解決這個問題，目前有二種較常見的驗證方式被引入，分別是基於 Session 及 Token 的驗證。而本文中主要是介紹基於 Token 驗證方式中的最常使用的 JSON Web Token (JWT)。

### 基於 Session 驗證原理
在過去的專案中大部分都是透過 Session 和 Cookie 實作驗證機制，主要的流程如下：

1. 首先瀏覽器會先將登入資訊 POST 給伺服器端進行
2. 伺服器端接收到請求後會進行驗證，若驗證成功會產生一組 Session
3. 伺服器端將 Session 傳回給瀏覽器並存在 Cookie 中
4. 若使用者的請求需要驗證則帶上 Cookie 並傳入伺服器端
5. 伺服器端根據 Cookie 來驗證 Session
6. 返回驗證資訊

<center>

![](https://i.imgur.com/txGaJAa.png)

</center>

不過對於這種驗證的方式會有幾個缺點：
1. 每次驗證後伺服器端都要產生一組新的 Session 並保存。當伺服器的使用者增加時，成本也將不斷提高，花費額外的效能
2. 如果 Session 是保存在記憶體中，也將不利於擴展。因為伺服器端做了負載平衡的話，請求若發向了伺服器A，但 Session 只保存在伺服器B，則將驗證失敗

### 基於 Token 的驗證原理
由於基於 Session 的驗證一些的限制，所以基於 Token 的方式因此誕生，它更符合 HTTP 的 Stateless 原則，在伺服器端不需要將用戶驗證完的狀態儲存起來。因此每次發出需要驗證的請求都將帶有伺服器端需要的使用者資訊，而流程大致上如下：
1. 首先瀏覽器會先將登入資訊 POST 給伺服器端進行
2. 伺服器端接收到請求後會進行驗證，若驗證成功會產生一組只有伺服器端能驗證的 JWT
3. 伺服器端將 Session 傳回給瀏覽器並存在客戶端中 (通常在瀏覽器中的 Storage)
4. 若使用者的請求需要驗證則在 header 的 Authorization 欄位帶上 JWT 並傳入伺服器端
5. 伺服器端根據 JWT 來驗證並取得使用者資訊
6. 返回驗證資訊

<center>

![](https://i.imgur.com/YD1sFGD.png)

</center>

而最常使用的 Token 驗證為 JWT

### 什麼是 JSON Web Token ?
JWT 是一個開放標準(RFC 7519)，它定義了一種簡潔且自我包含的方法，用於在雙方之間能安全地將訊息透過 JSON 進行傳輸。而這個訊息是透過數位簽章的，因此可以被驗證及信任

### JWT 的組成
JWT 是一組簡潔的字串，透過 ( . ) 分割成三個為 Base64 編碼的部分：
1. Header
2. Payload
3. Signature

因此，一個典型 JWT 的會長成這樣
```
base64(Header) + base64(Payload) + base64(Signature)
xxxxx.yyyyy.zzzz
```

#### Header
Header 通常包含二個部分：
1. Token 的類型
2. 產生簽章所使用的雜湊演算法，像是 HMAC、SHA256、RSA

例如：
```json=
{
    "alg": "HS256",
    "typ": "JWT"
}
```

#### Payload
包含 claims，而 claims 包含著用戶以及一些附加數據的聲明，通常有三種不同類型的 claims
1. **Registered claims**: 包含著一些育先定義的 claims，這些不是強制性的，而是推薦的，像是 iss (issuer)、exp (expiration time)、sub (subject)
3. **Public claims**: 可以由使用 JWT 的人隨意定義。不過為了避免衝突，不應該與[IANA JSON Web Token Registry](https://www.iana.org/assignments/jwt/jwt.xhtml)中定義的衝突
4. **Private claims**:

例如：
```json=
{
    "sub": "1234567890",
    "name": "John Doe",
    "admin": true
}
```

#### Signature
Signature 是將 Header、Payload、自己設定的 Secret，透過在 Header 中設定的雜湊演算法而產生的

由於 Secret 並未對外公開，因此伺服器端能在拿到 Token 後，透過解碼確認資料並未被竄改，以驗證對方的身分

###### tags: `Authentication` `Developement` `Software`