一文了解 JWT Token
在實際開發中,使用令牌認證,還有其他很多好處。掌握令牌認證的原理和實現方法,是 Go 語言開發者,必備的核心技能之一。
由於 miniblog 使用 JWT Token 進行身份認證,爲了降低學習難度併爲後續代碼實現奠定基礎,本節課將介紹 JWT 的核心內容。
JWT 認證流程
學習 JWT 的最佳方式是通過其認證流程理解其原理。認證流程如下圖所示。
上圖展示了 JWT 的認證流程,具體流程如下:
-
客戶端(通常是前端)通過用戶名和密碼進行登錄;
-
服務端收到請求後會驗證用戶名和密碼,若與數據庫記錄不一致,則認證失敗,若一致,則認證通過。認證通過後,服務端會簽發一個具有有效期的 Token 並返回給客戶端;
-
客戶端接收到 Token 後會將其緩存,例如存儲在瀏覽器的 Cookie 或本地存儲中,方便下次調用時使用;
-
客戶端在之後的每次 API 請求中攜帶緩存的 Token;
-
服務端接收到請求後會驗證請求中攜帶的 Token,驗證通過後繼續處理業務邏輯並返回數據;
-
如果 Token 快過期,前端會調用 Token 刷新接口續期 Token,避免用戶再次登錄。之後,會使用續期後的 Token 發送 API 請求。
提示:
Go 項目開發中,Token 有效期通常設置爲 2 小時。
JWT Token 格式
在 JWT 中,Token 由 Header、Payload、Signature 三部分組成,中間用英文點號(.
)隔開,並使用 Base64 編碼。JWT Token 示例如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkwNzgwMDUsImlhdCI6MTczNTQ3ODAwNSwibmJmIjoxNzM1NDc4MDA1LCJ4LXVzZXItaWQiOiJ1c2VyLXc2aXJrZyJ9.GromRG7kK90UfU_Q5iOSHs_xE-zSk0e0HLHqJQUjYMU
(1)Header 介紹
JWT Token 的 Header 中包含兩部分信息:Token 的類型和 Token 所使用的加密算法。JWT Header 示例如下:
{
"typ": "JWT",
"alg": "HS256"
}
上述示例表明,Token 類型是 JWT
,加密算法爲 HS256
(alg
支持多種加密算法)。
(2)Payload 載荷介紹
Payload 中攜帶了 Token 的具體內容,其中包含一些標準字段,當然也可以添加額外字段以表達更豐富的信息。這些信息可以用於更復雜的處理場景,例如記錄請求的用戶 ID、用戶名等。標準字段包括:
-
iss
:JWT Token 的簽發者; -
sub
:主題; -
exp
:JWT Token 的過期時間; -
aud
:接收 JWT Token 的一方; -
iat
:JWT Token 的簽發時間; -
nbf
:JWT Token 的生效時間; -
jti
:JWT Token 的唯一標識(ID)。
Payload 示例如下所示:
{
"id": 2,
"userID": "user-p7q78j",
"nbf": 1527931805,
"iat": 1527931805
}
(3)Signature 簽名介紹
Signature 是 Token 的簽名部分,其生成方式如下:
-
使用 Base64 對
header.payload
進行編碼; -
使用密鑰(Secret)對編碼後的內容進行加密,加密後的內容即爲 Signature。
密鑰相當於一個密碼,存儲在服務端,通常通過配置文件設置密鑰的值。
最終生成的 Token 如下所示:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkwNzgwMDUsImlhdCI6MTczNTQ3ODAwNSwibmJmIjoxNzM1NDc4MDA1LCJ4LXVzZXItaWQiOiJ1c2VyLXc2aXJrZyJ9.GromRG7kK90UfU_Q5iOSHs_xE-zSk0e0HLHqJQUjYMU
簽名後,服務端會返回生成的 Token。客戶端在下次請求時會攜帶該 Token,服務端收到 Token 後會解析出 header.payload
,然後使用相同的加密算法和密碼對 header.payload
再次加密,並將加密後的 Token 與收到的 Token 進行比對。如果二者相同,則驗證通過;如果不相同,則返回 HTTP 401 Unauthorized 錯誤。
JWT Token 生成示例
下述代碼展示了具體如何生成一個 JWT Token,通過代碼可以詳細的瞭解 Token 生成的方式:
#!/bin/bash
# 定義Header
HEADER='{"alg":"HS256","typ":"JWT"}'
# 定義Payload
PAYLOAD='{"exp":1739078005,"iat":1735478005,"nbf":1735478005,"x-user-id":"user-w6irkg"}'
# 定義Secret(用於簽名)
SECRET="Rtg8BPKNEf2mB4mgvKONGPZZQSaJWNLijxR42qRgq0iBb5"
# 1. Base64編碼Header
HEADER_BASE64=$(echo -n "${HEADER}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n')
# 2. Base64編碼Payload
PAYLOAD_BASE64=$(echo -n "${PAYLOAD}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n')
# 3. 拼接Header和Payload爲簽名數據
SIGNING_INPUT="${HEADER_BASE64}.${PAYLOAD_BASE64}"
# 4. 使用HMAC SHA256算法生成簽名
SIGNATURE=$(echo -n "${SIGNING_INPUT}" | openssl dgst -sha256 -hmac "${SECRET}" -binary | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n')
# 5. 拼接最終的JWT Token
JWT="${SIGNING_INPUT}.${SIGNATURE}"
# 輸出JWT Token
echo "Generated JWT Token:"
echo "${JWT}"
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ZVagoxaTg2IcA5RW9vYyBQ