FastAPI中間件:如何處理跨域、認證等請求攔截

FastAPI中間件:處理跨域、認證等請求攔截

在Web開發中,我們經常需要在請求到達後端處理邏輯之前,對請求進行統一檢查或處理。比如,判斷用戶是否有權限訪問API、處理前端跨域請求等。FastAPI的中間件(Middleware) 就是用來實現這類功能的“攔截器”——它可以在請求進入應用和響應返回之前,對請求數據進行修改、驗證或直接返回響應,讓我們能更靈活地控制請求的生命週期。

一、中間件是什麼?

簡單來說,中間件是一個函數,它會在請求到達路由函數之前(進入應用)和響應返回給客戶端之前(離開應用)被調用。你可以把它想象成一條“檢查線”:所有請求必須先通過這條線的檢查,才能繼續處理;響應返回前,也可以通過這條線做最後的調整。

每個中間件都有兩個核心作用:
1. 處理請求:在請求到達路由前,對請求數據進行驗證、修改或攔截。
2. 處理響應:在響應返回前,對響應數據進行統一處理(比如添加CORS頭、修改狀態碼等)。

中間件的執行順序非常重要:先註冊的中間件會先執行,返回時則相反(後註冊的先執行)。

二、處理跨域請求(CORS)

當你的前端頁面(比如http://localhost:3000)需要調用後端API(比如http://localhost:8000)時,瀏覽器會因爲“同源策略”阻止跨域請求(不同源:協議、域名、端口任意一個不同)。這時候就需要後端配置跨域資源共享(CORS),允許指定的前端源訪問API。

1. 安裝與配置CORS中間件

FastAPI通過CORSMiddleware處理CORS,需要先安裝fastapiuvicorn(如果還沒裝):

pip install fastapi uvicorn

然後在代碼中導入並配置中間件:

from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

app = FastAPI()

# 配置CORS中間件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允許的前端源,"*"表示所有源(開發環境用,生產環境建議指定具體域名)
    allow_credentials=True,  # 是否允許攜帶Cookie
    allow_methods=["*"],  # 允許的HTTP方法(GET/POST等),"*"表示所有方法
    allow_headers=["*"],  # 允許的請求頭,"*"表示所有頭信息
)

# 測試路由
@app.get("/api/hello")
async def hello():
    return {"message": "Hello, Cross-Origin!"}

2. 關鍵參數說明

  • allow_origins:允許的前端域名列表,生產環境必須寫具體域名(如["https://your-frontend.com"]),避免安全風險。
  • allow_methods:允許的HTTP方法(如["GET", "POST"]),不建議用"*"
  • allow_headers:允許的請求頭(如["Authorization"]),如果前端需要傳遞自定義頭(如Token),需在此列出。

三、認證攔截:驗證用戶身份

很多API需要驗證用戶身份(比如檢查Token),中間件可以在所有請求到達路由前統一攔截,驗證用戶是否有權限訪問。如果驗證失敗,直接返回“未授權”(401)錯誤,阻止請求進入路由函數。

1. 依賴項 vs 中間件

  • 依賴項:更靈活,針對特定路由或函數,需要顯式聲明在路由參數中。
  • 中間件:全局生效,無需在每個路由聲明,適合通用邏輯(如所有API都需要的認證檢查)。

這裏用中間件實現全局Token驗證

from fastapi import Depends, Request, HTTPException
from fastapi.security import OAuth2PasswordBearer

# 模擬Token驗證邏輯(實際項目中需用JWT等真實驗證)
def verify_token(token: str) -> bool:
    """驗證Token是否有效(示例:簡單檢查Token是否爲"valid_token")"""
    return token == "valid_token"

# OAuth2密碼流,獲取請求頭中的Token(前端通常放在Authorization: Bearer {token})
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# 定義認證中間件
class AuthMiddleware:
    async def __call__(self, request: Request, call_next):
        # 1. 獲取請求頭中的Token
        token = request.headers.get("Authorization")
        if not token or not token.startswith("Bearer "):
            raise HTTPException(status_code=401, detail="Token不存在或格式錯誤")

        # 2. 提取Token內容(去除"Bearer "前綴)
        token = token.split(" ")[1]

        # 3. 驗證Token
        if not verify_token(token):
            raise HTTPException(status_code=401, detail="Token無效或已過期")

        # 4. Token驗證通過,繼續執行下一個中間件或路由函數
        response = await call_next(request)
        return response

# 將中間件添加到FastAPI應用
app.add_middleware(AuthMiddleware)

# 測試路由(只有攜帶有效Token才能訪問)
@app.get("/api/protected")
async def protected_route():
    return {"message": "這是需要認證的API!"}

2. 如何測試?

啓動服務後,用curl或Postman測試:

# 攜帶有效Token(Token爲"valid_token")
curl -H "Authorization: Bearer valid_token" http://localhost:8000/api/protected

# 無效Token(返回401)
curl -H "Authorization: Bearer invalid_token" http://localhost:8000/api/protected

四、中間件的注意事項

  1. 執行順序:多箇中間件按註冊順序執行,返回時逆序。例如:
   app.add_middleware(Middleware1)
   app.add_middleware(Middleware2)

請求會先經過Middleware1,再Middleware2,最後到路由;返回時先經過Middleware2,再Middleware1

  1. 避免過度攔截:中間件邏輯要簡潔,避免複雜計算或數據庫操作,否則會影響性能。

  2. 區分場景:通用邏輯(如CORS、全局認證)用中間件;局部邏輯(如特定路由的權限)用依賴項。

總結

中間件是FastAPI中處理請求攔截的“瑞士軍刀”,能幫我們實現跨域處理、全局認證、日誌記錄等功能。通過CORSMiddleware解決前端跨域問題,通過自定義中間件實現全局認證,讓API開發更高效、安全。

小技巧:開發時先用allow_origins=["*"]快速調試跨域,生產環境務必替換爲具體域名;認證中間件要優先處理Token驗證,確保邏輯清晰、錯誤提示明確。

現在,你可以嘗試在自己的FastAPI項目中添加中間件,讓API更健壯吧!

小夜