FastAPI 鉴权怎么写?中间件和依赖注入一次说清楚

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() = 验证逻辑挂在哪个接口,就只作用于哪个接口。

从重复写验证代码的痛点出发,到抽出来统一管理,就是这两个东西存在的全部理由。

相关推荐
动力 continue3 分钟前
Python 元类与异常类:类的“制造工厂”与“报错定制师”
开发语言·python·制造
147API11 分钟前
Python批量生成蒸馏数据,并发、重试、幂等和断点续跑
开发语言·jvm·python
青 春 记 忆13 分钟前
零基础入门python04:用注册校验理解字典、集合和条件判断
开发语言·vscode·python·python3.11
kels889917 分钟前
实战排坑:黄金实时API开发,XAUUSD Tick报文异常处理实践
开发语言·python·websocket·网络协议·信息可视化
FBI HackerHarry浩24 分钟前
Pandas 库中用于分类变量独热编码(One-Hot Encoding)的函数 pd.get_dummies() 函数
开发语言·人工智能·python·pandas
高洁0131 分钟前
工信部教考中心证书-人工智能系列本系列
人工智能·python·深度学习·算法
李可以量化1 小时前
Tornado 从入门到精通(二)下:协程调用方式与经典使用模式
python
雪碧透心凉_1 小时前
Python OpenCV图像处理入门
图像处理·python·opencv
李可以量化1 小时前
Tornado 从入门到精通(二)上:协程核心机制详解
python
晴天161 小时前
AgentLoop分享(上): 让 AI 真正“自主干活“-Day15
人工智能·python