FastAPI 鉴权:中间件 & 依赖注入
用来干啥?
你把 Agent 包装成 API 对外提供服务,总不能让任何人都能随便调用。
中间件和依赖注入就是用来解决这个问题的:在请求到达业务代码之前,先验证这个人有没有资格调用。
没有它们,会怎样?
最直觉的写法是每个接口自己验证:

python
@app.post("/agent")
async def run_agent(request: Request):
token = request.headers.get("X-Api-Key")
if token not in VALID_KEYS:
raise HTTPException(403)
# 业务逻辑...
@app.get("/history")
async def get_history(request: Request):
token = request.headers.get("X-Api-Key")
if token not in VALID_KEYS:
raise HTTPException(403)
# 业务逻辑...
同样的验证代码写了两遍,10 个接口就写 10 遍。 哪天改个验证规则,漏改一处就是安全漏洞。
解法一:中间件
一句话:在门口拦所有人,验证通过才放行。

python
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse
VALID_API_KEYS = {"sk-team-alpha-xxx", "sk-team-beta-yyy"}
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
api_key = request.headers.get("X-Api-Key", "")
if api_key not in VALID_API_KEYS:
return JSONResponse({"detail": "Unauthorized"}, status_code=403)
return await call_next(request) # 验证通过,放行
app.add_middleware(AuthMiddleware)
加了中间件之后,所有接口不用再写验证代码,中间件统一处理:
客户端 → [中间件验证] → /agent 只管业务
→ /history 只管业务
→ /session 只管业务
解法二:Depends()
中间件是"拦所有人"。但有时候你需要更精细的控制:
/health健康检查,不需要验证/agent需要验证 API Key/admin需要验证管理员权限
这时候用 Depends(),把验证函数挂到指定路由上,只拦这一个。

第一步,写验证函数:
python
async def require_api_key(x_api_key: str = Header(...)):
if x_api_key not in VALID_API_KEYS:
raise HTTPException(status_code=403, detail="Invalid API Key")
return x_api_key
第二步,挂到需要的路由上:
python
@app.post("/agent")
async def run_agent(
payload: AgentRequest,
api_key: str = Depends(require_api_key), # 挂上去
):
# 能走到这里说明已经验证通过了
response = executor.invoke({"input": payload.input})
return {"output": response["output"]}
框架会在执行 run_agent 之前,自动调用 require_api_key,通过了才继续,不通过直接 403。
两者怎么选?
| 中间件 | Depends() | |
|---|---|---|
| 一句话 | 在门口拦所有人 | 在某个房间门口单独拦 |
| 适合场景 | 所有接口统一验证 | 不同接口不同权限 |
实际项目里两者经常组合用:CORS、日志这种全局的事情交给中间件,具体接口的权限控制交给 Depends()。
区别图:

完整代码
python
from fastapi import FastAPI, Depends, HTTPException, Header
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
app = FastAPI()
# 全局 CORS 中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
VALID_API_KEYS = {"sk-team-alpha-xxx", "sk-team-beta-yyy"}
# 验证函数
async def require_api_key(x_api_key: str = Header(...)):
if x_api_key not in VALID_API_KEYS:
raise HTTPException(status_code=403, detail="Invalid API Key")
return x_api_key
# 公开接口
@app.get("/health")
def health():
return {"status": "ok"}
# 受保护接口
class AgentRequest(BaseModel):
input: str
@app.post("/agent")
async def run_agent(
payload: AgentRequest,
api_key: str = Depends(require_api_key),
):
response = executor.invoke({"input": payload.input})
return {"output": response["output"]}
总结
中间件 = 验证逻辑只写一次,所有接口共享。
Depends() = 验证逻辑挂在哪个接口,就只作用于哪个接口。
从重复写验证代码的痛点出发,到抽出来统一管理,就是这两个东西存在的全部理由。