跳到主要內容

發表文章

目前顯示的是 7月, 2025的文章

Web Day 13 OAuth2 與角色授權

Web Day 13 OAuth2 與角色授權 執行需求:CPU 可跑 。昨天我們用 JWT 做出「登入 → 發 token → 驗 token → 取得目前使用者」這套基本流程。今天要把昨天的基礎延伸成「角色授權」:讓 API 能區分「一般使用者」與「管理者」,並在端點上宣告「只有管理者能呼叫」。我們會用 FastAPI 的 Security 與 SecurityScopes 實作 OAuth2 scope 概念,並設計 require_role 與 require_admin 兩支可重複使用的相依性,後續的「預約管理系統」專案篇(Web Day 35+)會直接沿用這套設計。 引言 昨天的 JWT 認證解決了「你是誰」的問題,但還沒處理「你能做什麼」。在真實系統裡,使用者通常分幾種角色:訪客(未登入)、一般使用者(可以建立訂單、查自己的資料)、管理者(可以查所有訂單、刪除違規內容)。如果每個端點都自己寫「檢查使用者的角色」的程式碼,會出現幾個問題:第一,邏輯散落在各處,難以統一審查;第二,新人很容易在某個端點忘了檢查角色,導致權限漏洞;第三,OAuth2 規範定義的 scope 概念無法落實。 「授權」(authorization)和「認證」(authentication)是兩件事。認證是「你是誰」,授權是「你能做什麼」。昨天的 JWT 處理認證,今天處理授權。常見的授權模型有 RBAC(Role-Based Access Control)與 ABAC(Attribute-Based Access Control),前者以角色為中心、後者以屬性為中心。我們今天用 RBAC,因為它最直覺、SQL 表格也簡單,適用於大多數後端系統。RBAC 的優點是角色數量通常很少(管理員、一般使用者、編輯者等),新增角色只要加 enum 值;缺點是當業務複雜度提升,「角色」與「權限」變得多對多時,維護成本會迅速上升。ABAC 則是用條件表達式(例如「使用者只能改自己的資料」「管理者只能改同部門的資料」),靈活度高但實作複雜,適合企業級應用。多數新專案從 RBAC 開始,等真的碰到複雜情境再升級,是務實的選擇。 今天的目標有三個:第一,把昨天的 User 模型擴充成支援角色(用 enum);第二,設計 require_role(...) 與 requ...

Web Day 14 檔案上傳與靜態檔案

Web Day 14 檔案上傳與靜態檔案 執行需求:CPU 可跑 。前幾天我們處理的是純文字資料(JSON、密碼、token),今天進入「檔案」的世界。你會學到 FastAPI 的 UploadFile 與 File 怎麼處理使用者上傳的頭像或附件、怎麼限制檔案大小與 MIME 型別、怎麼用隨機檔名避免衝突與覆寫攻擊,以及 StaticFiles 怎麼把上傳後的檔案透過 URL 對外提供。最後我們會做完整的「使用者頭像上傳 → 儲存 → 透過 URL 顯示」流程,這是後續「預約管理系統」中客戶頭像與預約附件功能的基礎。 引言 後端 API 處理的資料大致分兩類:純文字(JSON、表單欄位)與二進位檔案(圖片、PDF、影片)。到目前為止,我們處理的都是純文字。但真實世界的應用幾乎都需要處理檔案:社群平台要存使用者頭像、電商網站要存商品照片、教育平台要讓學生交作業 PDF、預約系統要讓店家上傳服務照片。如果後端不處理檔案,前端只能把檔案編碼成 base64 塞進 JSON,不僅浪費頻寬,記憶體也吃很重。 FastAPI 對檔案處理有兩種層次的支援:第一種是 File 與 Form ,處理傳統 multipart/form-data 上傳;第二種是 UploadFile ,把上傳的檔案包成一個非同步可讀的物件,搭配 spooled temporary file 機制,小檔案放記憶體、大檔案自動 spill 到磁碟。對絕大多數應用來說 UploadFile 是正確選擇。我們今天就用它。 UploadFile 內部使用 Python 的 SpooledTemporaryFile :當檔案小於某個臨界值(預設 1 MB)時,內容放在記憶體中的 BytesIO ,讀取非常快;超過臨界值則自動切換到磁碟上的暫存檔,避免 OOM。這套機制讓 FastAPI 對 100 KB 的頭像與 1 GB 的影片都能用同一支 API 處理,開發者不必為不同大小的檔案寫兩套程式。 今天的目標有四個:第一,理解 UploadFile 的設計與限制;第二,建立「上傳頭像」端點,含大小、MIME 型別、檔名安全檢查;第三,建立 StaticFiles 把上傳目錄對外提供為靜態 URL;第四,把檔案路徑存進 User 模型,讓前端可以用統一的 URL 顯示頭像。整個...

Web Day 12 JWT 認證:登入與 token 驗證

Web Day 12 JWT 認證:登入與 token 驗證 執行需求:CPU 可跑 。昨天完成了註冊流程,密碼以 argon2id 雜湊儲存;今天進入「登入」與「token 驗證」。你會學到 JWT(JSON Web Token)的三個組成部分(header、payload、signature)、 exp 與 iat 這類標準 claim 的意義、access token 與 refresh token 的分工,並用 PyJWT 2.10 寫出完整的「登入端點」、「刷新 token 端點」、「需登入的端點範例」。這套認證機制會是 Web Day 13「OAuth2 與角色授權」的基礎。 引言 註冊只解決了「使用者怎麼加入系統」,但每次使用者要查詢自己的資料、修改設定、刪除訂單,伺服器怎麼知道「這個請求真的是 Alice 送來的」?最直覺的做法是用 session:伺服器保留一份「Alice 已登入」的記錄,使用者帶一個 session id 來對照。但這套機制有兩個限制:第一,伺服器必須儲存所有使用者的 session 狀態,部署到多台機器時需要共享儲存(例如 Redis);第二,對純 API 場景(特別是 mobile app 或 SPA),cookie-based session 容易受到 CSRF 攻擊,需要額外防護。 JWT(JSON Web Token)是另一條路。它把「已登入」的狀態編碼進 token 本身:伺服器簽發一段包含使用者資訊的 JSON,用祕密簽名後交給前端;之後前端每次請求都帶這段 token,伺服器只要驗證簽名就能確認「這個 token 是我發的、內容沒被改過」。伺服器不需要存任何 session 狀態,這就是「無狀態」(stateless)認證的核心概念。 今天目標有四個:第一,理解 JWT 的結構與標準 claim;第二,用 PyJWT 2.10 實作「簽發 access token」「簽發 refresh token」「驗證 token」三個工具函式;第三,建立「登入端點」驗證密碼並回傳 token;第四,建立「需登入的端點範例」示範如何從 token 取出目前使用者。整篇文章的範例沿用昨天的 User 模型與昨天的 argon2id 密碼驗證。 JWT 的三個部分 一個 JWT 看起來像這樣:...