iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0

簡介

應用程式通常需要驗證使用者身份,並確認其是否具備執行特定操作的權限。以購物網站為例,系統首先需要識別使用者的身份,然後再確認該使用者是否擁有上架或下架商品的權限。前者的過程稱為身份驗證(Authentication),而後者則是授權(Authorization)。

目前主流的身份驗證與授權方式多採用 JWT(JSON Web Token)。顧名思義,JWT 是一種以 JSON 格式表示的憑證,通常包含使用者的身份資訊和授權權限等重要資料。它常用於系統間的網路傳輸,以確保數據的完整性與安全性。此外,許多 Web 應用程式會使用第三方認證,例如 Google 和 Facebook 登入,這些流程通常也會採用 JWT 作為憑證。

在憑證中有兩個重要角色。第一個角色是憑證的發行者,負責驗證使用者的身份及其授權,並將結果寫入憑證後發行。第二個角色是憑證的接收者,接收憑證後根據其中的使用者資訊進行後續邏輯判斷。

https://ithelp.ithome.com.tw/upload/images/20240929/20168663w8mRmMuJtJ.png

以上圖為例,該圖來自於 jwt.io 的官方示例。整體圖片分為兩大區域:左側的 Encoded 區域和右側的 Decoded 區域。在左側的 Encoded 區域中,可以看到一串類似亂碼的憑證,它主要用於系統間的傳輸,是經過 Base64 編碼的結果。該編碼字串由三個部分組成,分別用紅色、紫色和藍色區塊表示,並以 . 進行區隔。這三個區塊經過解碼後,分別對應到右側 Decoded 區域中的 HEADERPAYLOAD 以及 VERIFY SIGNATURE

首先介紹 HEADER,它表示該憑證的類型以及使用的加密演算法。接下來是最重要的 PAYLOAD 區塊,這裡包含使用者的身份資訊和授權紀錄。範例中的 subiat 是保留字,前者 sub(subject)代表使用者 ID,而後者 iat(Issued At)則表示該憑證的發行時間。name 是憑證額外擴充的屬性,代表使用者名稱。由於憑證中已帶有使用者的相關資訊,因此憑證的接收者可以直接根據憑證的內容進行後續的邏輯判斷。

由於 PAYLOAD 本身僅透過簡單的 Base64 轉換,因此其中的資訊容易被竄改。例如,若 PAYLOAD 中的 sub 值為 1234567890,那麼使用者 1234567890 可以讀取自己的購買紀錄。然而,惡意人士如果將 sub 值竄改為 111111111,就可能竊取 111111111 的購買紀錄。為了增強 JWT 的安全性,JWT 透過第三個區塊 VERIFY SIGNATURE 來防止憑證被輕易篡改。憑證的發行者會將 HEADERPAYLOAD 的資訊合併成一個字串,並使用加密演算法對該字串進行加密,最終生成 VERIFY SIGNATURE 的亂碼字串。當憑證的接收者獲取憑證時,首先需要根據 VERIFY SIGNATURE 驗證憑證是否遭到篡改。關於加密演算法的概念,下一篇將進行更詳細的介紹,本篇暫時跳過。

在 Python 環境中,通常會使用 PyJWT 套件來處理 JWT 憑證的發行與接收。接下來,我將通過範例進行介紹。

範例

本次範例使用的是 PyJWT 2.9.0 版本

poetry add PyJWT==2.9.0

本次範例分為三個部分:第一部分是設定檔,用於配置加密演算法的參數;第二部分是憑證的發行者;最後,第三部分則是憑證的接收者。

Setting

開發者可以使用 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

建立 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 即可看到發行的憑證。
https://ithelp.ithome.com.tw/upload/images/20240929/20168663tqa7BQ3wv0.png

Decode

建立 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 資訊。
https://ithelp.ithome.com.tw/upload/images/20240929/20168663BYc2gTQuPW.png


上一篇
[Day 15] Asyncio
下一篇
[Day 17] Cryptography
系列文
Python 不止於數據,開發應用程式它也在行!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言