前言
JWT 是 JSON Web Token 的縮寫。在寫此篇時,發現已經有許多相關文章可參考,故本篇以實作為主,若想知道更深入部分,可直接看參考資料
JWT組成
由 Header
、Payload
、 Signature
所組成的字串,中間以 .
做間隔
1
2
3
4
5# 寫成一行的話,組成如下
Header.Payload.Signature
# 實際範例如下 (中間以 . 做間隔)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
組成 | 說明 |
---|---|
Header | 通常由演算法簽章、 Token 類型所組成的 JSON,再做 Base64 URL 編碼 |
Payload | 需傳遞的資料放這 |
Signature | Header、Payload、密鑰 (secret) 透過雜湊演算法所產生 |
最終資料呈現如下方圖左,是一個字串
動手做看看
官方 JWT 首頁已有範例,這邊以 Ruby 做演練
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27# 在 irb 中操作
require "json"
require "base64"
require "openssl"
header = { "alg" => "HS256", "typ" => "JWT" }
header_json = header.to_json # or JSON(header)
encoded_header = Base64.urlsafe_encode64(header_json, padding: false) # Base64 編碼 header
payload = { "sub" => "1234567890", "name" => "John Doe", "iat" => 1516239022 }
payload_json = payload.to_json # or JSON(payload)
encoded_payload = Base64.urlsafe_encode64(payload_json, padding: false) # Base64 編碼 payload
secret_key = "your-256-bit-secret"
data = "#{encoded_header}.#{encoded_payload}"
digest = OpenSSL::Digest::SHA256.new # 使用 SHA256 演算法
signature = OpenSSL::HMAC.digest(digest, secret_key, data) # 透過 HMAC 演算法簽章
encoded_signature = Base64.urlsafe_encode64(signature, padding: false) # Base64 編碼 signature
token = "#{encoded_header}.#{encoded_payload}.#{encoded_signature}"
# 驗證,與 JWT 首頁範例一樣
token == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
使用 RubyGems
上述為手動實作,透過實作能更清楚如何運作 也可直接使用 jwt gem 來處理,一切變得簡單多了,有興趣可看下 source code 部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 使用 ruby-jwt gem 實作
hmac_secret = "your-256-bit-secret"
payload = { "sub" => "1234567890", "name" => "John Doe", "iat" => 1516239022 }
token = JWT.encode payload, hmac_secret, "HS256"
decoded_token = JWT.decode token, hmac_secret, true, { algorithm: "HS256" }
# # Array (payload + header)
# [
# {
# "sub" => "1234567890",
# "name" => "John Doe",
# "iat" => 1516239022
# },
# {
# "alg" => "HS256"
# }
# ]
小結
JWT 的特色有「JSON 通用性的關係,可跨語言使用」、「構造簡單,size 小,便於傳輸」...等
在使用 JWT 時,不建議把敏感資料放裡面,只要解碼 Base64 便能看到原本的資料
推薦下面參考資料可以都看過一輪
參考資料
- https://jwt.io/
- JSON Web Token Wiki
- ruuby-jwt
- 是誰在敲打我窗?什麼是 JWT ?
- 見令如見人,介紹 JWT
- [筆記] 透過 JWT 實作驗證機制
- JSON Web Token 入门教程
- JSON Web Token(JWT) 簡單介紹
鐵人賽文章連結:https://ithelp.ithome.com.tw/articles/10264580
medium 文章連結:https://link.medium.com/OYkJftn2Mjb
本文同步發布於 小菜的 Blog https://riverye.com/
備註:之後文章修改更新,以個人部落格為主