本文 AI 產出,尚未審核

FastAPI 課程:Session 與 Cookie 管理

主題:回傳 Response 時設定 Cookie


簡介

在 Web 應用程式中,Cookie 是最常見的客戶端狀態保存機制之一。它可以用來記錄使用者的登入資訊、偏好設定、追蹤分析資料等。FastAPI 作為一個高效能的 Python Web 框架,提供了直觀且彈性的方式在 Response 中設定、讀取與刪除 Cookie,讓開發者可以輕鬆完成 Session 管理、驗證流程等需求。

本篇文章將從 概念說明實作範例常見陷阱與最佳實踐,以及 實務應用場景 四個面向,完整介紹在 FastAPI 中如何於回傳 Response 時設定 Cookie,幫助初學者快速上手,同時提供中階開發者更深入的技巧與注意事項。


核心概念

1. Cookie 的基本原理

  • Cookie 是由伺服器在 HTTP 回應的 Set-Cookie 標頭中設定,瀏覽器收到後會自動在後續對同一站點的請求中帶上 Cookie 標頭。
  • 每個 Cookie 包含 名稱 (name)值 (value)、以及可選的屬性,如 ExpiresMax-AgeDomainPathSecureHttpOnlySameSite 等。
  • 正確設定屬性可以提升安全性(例如 HttpOnly 防止 JavaScript 讀取)與相容性(例如 SameSite 防止 CSRF)。

2. FastAPI 中的 Response 物件

FastAPI 內部使用 Starlette 作為底層 ASGI 框架,fastapi.Response 繼承自 starlette.responses.Response

  • 直接建立 ResponseJSONResponseHTMLResponse 等物件時,都可以透過 set_cookie() 方法加入 Cookie。
  • 若使用 依賴注入 (Dependency Injection)路由函式回傳字典,FastAPI 會自動轉換成 JSONResponse,此時仍可在函式內取得 Response 物件並設定 Cookie。

3. Response.set_cookie() 參數說明

參數 型別 說明
key str Cookie 名稱
value str Cookie 值
max_age int | None Cookie 的存活秒數,None 表示使用 expires
expires int | datetime | None 絕對過期時間
path str Cookie 所屬路徑,預設 /
domain str | None 所屬網域,如 .example.com
secure bool 是否僅在 HTTPS 中傳送
httponly bool 是否禁止 JavaScript 存取
samesite str | None laxstrictnone,控制跨站請求行為

4. 取得與刪除 Cookie

  • 取得:在路由函式中,可透過 request.cookies.get("cookie_name") 取得。
  • 刪除:使用 response.delete_cookie(key, path='/', domain=None),實際上是設定一個已過期的 Cookie。

程式碼範例

以下範例均以 Python 3.9+FastAPI 0.110+ 為前提,建議使用 uvicorn 作為 ASGI 伺服器。

範例 1:最簡單的 Set-Cookie

from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/set-cookie")
def set_simple_cookie(response: Response):
    """
    在回應中設定一個名為 `my_cookie`、值為 `hello` 的 Cookie。
    """
    response.set_cookie(key="my_cookie", value="hello")
    return {"message": "Cookie 已設定"}

說明

  • 只要在路由函式參數中加入 response: Response,FastAPI 會自動注入 Response 物件。
  • set_cookie 只需要 keyvalue,其餘屬性使用預設值(path='/'secure=False 等)。

範例 2:設定 HttpOnly 與 Secure

from fastapi import FastAPI, Response

app = FastAPI()

@app.post("/login")
def login(response: Response, username: str, password: str):
    """
    假設已完成使用者驗證,接著發放 JWT 並以 HttpOnly Cookie 回傳。
    """
    # 這裡省略驗證邏輯,直接產生 token
    token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    # 設定 Cookie,僅在 HTTPS 下傳送,且無法被 JS 讀取
    response.set_cookie(
        key="access_token",
        value=token,
        httponly=True,
        secure=True,        # 只在 HTTPS 中傳送
        max_age=3600,       # 1 小時後過期
        samesite="lax"
    )
    return {"message": "登入成功"}

重點

  • httponly=True 能防止 XSS 攻擊竊取 token。
  • secure=True 確保 Cookie 只在加密連線下傳送,避免被中間人竊聽。

範例 3:同時回傳 JSON 與多個 Cookie

from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/multi-cookie")
def multi_cookie(response: Response):
    """
    同時設定使用者偏好與語系資訊的兩個 Cookie。
    """
    response.set_cookie(key="theme", value="dark", max_age=30*24*60*60)   # 30 天
    response.set_cookie(key="locale", value="zh-TW", max_age=30*24*60*60)
    return {"message": "多個 Cookie 已設定"}

說明

  • set_cookie 可以被呼叫多次,FastAPI 會在同一個回應中產生多個 Set-Cookie 標頭。

範例 4:讀取 Cookie 並回傳相應資料

from fastapi import FastAPI, Request, HTTPException

app = FastAPI()

@app.get("/profile")
def get_profile(request: Request):
    """
    讀取 `access_token` Cookie,若不存在則拋出 401。
    """
    token = request.cookies.get("access_token")
    if not token:
        raise HTTPException(status_code=401, detail="未登入")
    # 假設此處會驗證 token 並取得使用者資訊
    user_info = {"username": "alice", "role": "admin"}
    return {"user": user_info}

提示

  • request.cookiesMutableMapping[str, str],直接使用 get 取得值。

範例 5:刪除 Cookie(登出)

from fastapi import FastAPI, Response

app = FastAPI()

@app.post("/logout")
def logout(response: Response):
    """
    透過 `delete_cookie` 讓瀏覽器移除 `access_token`。
    """
    response.delete_cookie(key="access_token", path="/")
    return {"message": "已登出"}

說明

  • delete_cookie 會設定一個已過期的同名 Cookie,瀏覽器收到後會自動刪除。

常見陷阱與最佳實踐

陷阱 可能的後果 解決方式 / 最佳實踐
忘記設定 httponly XSS 攻擊者可透過 JavaScript 竊取敏感資訊(如 JWT) 預設將所有認證相關 Cookie 設為 httponly=True
在開發環境使用 secure=True 本機測試時無法收到 Cookie,導致認證失效 在本機開發時可使用環境變數切換 secure,或使用 if not DEBUG: secure=True
SameSite=None 卻未同時設定 Secure 現代瀏覽器會拒絕該 Cookie,導致跨站請求失敗 規則:若 SameSite="none" 必須同時 secure=True
Cookie 大小超過 4KB 瀏覽器會截斷或直接拋棄,導致資料遺失 建議:僅存放必要資訊,使用伺服器端 Session 或 JWT 代替大型資料
使用相同 key 卻不同 path 可能產生多個同名 Cookie,造成混淆 統一 path(通常為 /)或在設計時明確區分命名空間
未設定 max_ageexpires Cookie 為 Session Cookie,關閉瀏覽器即失效 根據需求決定存活時間,若需要長期記錄則設定 max_age(秒)或 expires(datetime)

最佳實踐清單

  1. 安全第一:所有認證或敏感資料的 Cookie 必須 httponly=Truesecure=Truesamesite="lax"(或 strict)。
  2. 最小化 Cookie 大小:僅存放 token、session id,其他資訊放在資料庫或快取。
  3. 統一命名規則:例如 app_{purpose},避免與第三方或前端自行設定的 Cookie 衝突。
  4. 環境切換:使用 settings.py 或環境變數管理 securedomainsamesite 等屬性。
  5. 測試跨瀏覽器相容性:特別留意 Safari、Chrome 近期對 SameSite 的實作差異。

實際應用場景

1. 使用者登入與 JWT Cookie

在大多數單頁應用(SPA)中,前端會在每次 API 請求時自動帶上 Authorization: Bearer <token>。若希望降低前端管理的複雜度,可改為 將 JWT 放入 HttpOnly Cookie,讓瀏覽器自動傳送。

  • 優點:前端不需要手動儲存或注入 token,降低 XSS 風險。
  • 缺點:若需要在前端取得使用者資訊,需要額外提供 /me 之類的 API 讀取 Cookie 中的 token。

2. 語系與主題偏好

網站常會根據使用者的語系 (locale) 或主題 (theme) 設定 UI。將這類資訊寫入 長期 Cookie(如 30 天)可讓使用者每次訪問時自動套用個人化設定,且不需要登入。

response.set_cookie(key="theme", value="light", max_age=30*24*60*60)
response.set_cookie(key="locale", value="en-US", max_age=30*24*60*60)

3. 防止 CSRF 的 Double Submit Cookie

在某些不想使用 CSRF Token 的情況下,可採用 Double Submit Cookie:在登入時同時在 Cookie 與表單隱藏欄位寫入同一隨機字串,伺服器驗證兩者是否一致。

  • 實作要點
    1. response.set_cookie(key="csrf_token", value=rand_str, httponly=False, samesite="strict")
    2. 前端在每次表單提交時,將 Cookie 中的 csrf_token 讀取並放入隱藏欄位。
    3. 伺服器比對兩者是否相同。

4. 多租戶 (SaaS) 系統的 Domain Cookie

若系統支援 子域名(如 tenant1.example.comtenant2.example.com),可在設定 Cookie 時指定 domain=".example.com",讓所有子域共享同一個認證 Cookie。

response.set_cookie(
    key="session_id",
    value=session_id,
    domain=".example.com",
    path="/",
    httponly=True,
    secure=True,
    samesite="lax"
)

總結

  • Cookie 是瀏覽器與伺服器之間最簡單、最廣泛使用的狀態保存方式。
  • FastAPI 中,只需要在路由函式取得 Response 物件,呼叫 set_cookie()delete_cookie() 即可完成設定與刪除。
  • 安全屬性httponlysecuresamesite)是防止 XSS、CSRF、MITM 攻擊的關鍵,務必在所有認證相關 Cookie 中啟用。
  • 透過 範例 我們展示了從最簡單的單一 Cookie、到多 Cookie、到 JWT 認證與跨域設定的完整流程。
  • 最佳實踐 包括:最小化 Cookie 大小、統一命名、環境化設定、測試相容性,這些都能讓你的應用在開發與上線後更安全、更穩定。

掌握了上述概念與技巧,你就能在 FastAPI 專案中自如地管理 Session 與 Cookie,為使用者提供流暢且安全的體驗。祝開發順利!