應用程式通常需要驗證使用者身份,並確認其是否具備執行特定操作的權限。以購物網站為例,系統首先需要識別使用者的身份,然後再確認該使用者是否擁有上架或下架商品的權限。前者的過程稱為身份驗證(Authentication),而後者則是授權(Authorization)。
目前主流的身份驗證與授權方式多採用 JWT(JSON Web Token)。顧名思義,JWT 是一種以 JSON 格式表示的憑證,通常包含使用者的身份資訊和授權權限等重要資料。它常用於系統間的網路傳輸,以確保數據的完整性與安全性。此外,許多 Web 應用程式會使用第三方認證,例如 Google 和 Facebook 登入,這些流程通常也會採用 JWT 作為憑證。
在憑證中有兩個重要角色。第一個角色是憑證的發行者,負責驗證使用者的身份及其授權,並將結果寫入憑證後發行。第二個角色是憑證的接收者,接收憑證後根據其中的使用者資訊進行後續邏輯判斷。
以上圖為例,該圖來自於 jwt.io
的官方示例。整體圖片分為兩大區域:左側的 Encoded
區域和右側的 Decoded
區域。在左側的 Encoded
區域中,可以看到一串類似亂碼的憑證,它主要用於系統間的傳輸,是經過 Base64 編碼的結果。該編碼字串由三個部分組成,分別用紅色、紫色和藍色區塊表示,並以 .
進行區隔。這三個區塊經過解碼後,分別對應到右側 Decoded
區域中的 HEADER
、PAYLOAD
以及 VERIFY SIGNATURE
。
首先介紹 HEADER
,它表示該憑證的類型以及使用的加密演算法。接下來是最重要的 PAYLOAD
區塊,這裡包含使用者的身份資訊和授權紀錄。範例中的 sub
和 iat
是保留字,前者 sub
(subject)代表使用者 ID,而後者 iat
(Issued At)則表示該憑證的發行時間。name
是憑證額外擴充的屬性,代表使用者名稱。由於憑證中已帶有使用者的相關資訊,因此憑證的接收者可以直接根據憑證的內容進行後續的邏輯判斷。
由於 PAYLOAD
本身僅透過簡單的 Base64 轉換,因此其中的資訊容易被竄改。例如,若 PAYLOAD
中的 sub
值為 1234567890
,那麼使用者 1234567890
可以讀取自己的購買紀錄。然而,惡意人士如果將 sub 值竄改為 111111111
,就可能竊取 111111111
的購買紀錄。為了增強 JWT 的安全性,JWT 透過第三個區塊 VERIFY SIGNATURE
來防止憑證被輕易篡改。憑證的發行者會將 HEADER
和 PAYLOAD
的資訊合併成一個字串,並使用加密演算法對該字串進行加密,最終生成 VERIFY SIGNATURE
的亂碼字串。當憑證的接收者獲取憑證時,首先需要根據 VERIFY SIGNATURE
驗證憑證是否遭到篡改。關於加密演算法的概念,下一篇將進行更詳細的介紹,本篇暫時跳過。
在 Python 環境中,通常會使用 PyJWT 套件來處理 JWT 憑證的發行與接收。接下來,我將通過範例進行介紹。
本次範例使用的是 PyJWT 2.9.0 版本
poetry add PyJWT==2.9.0
本次範例分為三個部分:第一部分是設定檔,用於配置加密演算法的參數;第二部分是憑證的發行者;最後,第三部分則是憑證的接收者。
開發者可以使用 Pydantic Setting 來定義設定檔。在第 12 天的教學中已經介紹過 Pydantic Setting,這裡將簡單敘述其用法。首先,建立 settings.py
檔案,並定義 secret_key
參數,該參數將用於加密演算法。
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8')
secret_key: str
settings = Settings()
接著,建立 .env
檔案,並根據需求調整相應的參數。
SECRET_KEY=s82mlaj_wj1
建立 issue.py
檔案,其中 PAYLOAD
的資訊包含使用者 ID 及其角色,而角色為 admin
,表示該使用者為管理員,擁有所有權限。接著,使用 settings.py
中的設定參數來加密並發行憑證。
import jwt
from settings import settings
payload = {
'sub': 12345,
'role': 'admin',
}
token = jwt.encode(payload, settings.secret_key, algorithm='HS256')
print(f"issue token: {token}")
執行 poetry run python issue.py
即可看到發行的憑證。
建立 decode.py
檔案,接收者將使用 settings.py
中的設定參數來驗證憑證是否遭到篡改,並解析 PAYLOAD
的資訊,以便進行後續的邏輯判斷。
import jwt
from settings import settings
token = input("token:")
decoded_payload = jwt.decode(token, settings.secret_key, algorithms=['HS256'])
print(f"payload: {decoded_payload}")
執行 poetry run python decode.py
即可看到解析後的 PAYLOAD
資訊。