32. FastAPI 依赖注入_路由级
为整个 APIRouter 统一附加依赖
后台管理下的十几个接口都要相同检查时,在每个装饰器上重复填写容易漏写。路由级依赖可以绑定到一个 APIRouter,或在 include_router 时追加,覆盖该路由集合的操作。
最小完整示例
python
from typing import Annotated
from fastapi import APIRouter, Depends, FastAPI, Header, HTTPException
app = FastAPI()
def check_admin_demo(
x_study_role: Annotated[str | None, Header()] = None,
):
if x_study_role != "admin":
raise HTTPException(403, "需要管理员权限")
admin = APIRouter(prefix="/admin", tags=["管理"],
dependencies=[Depends(check_admin_demo)])
@admin.get("/users")
def users():
return [{"id": 1, "name": "小明"}]
@admin.get("/reports")
def reports():
return {"count": 10}
@app.get("/public")
def public():
return {"message": "公开"}
app.include_router(admin, prefix="/api/v1")保存为 main.py 并启动。访问 /api/v1/admin/users 和 /api/v1/admin/reports 都需要 X-Study-Role: admin;/public 不需要。
这个头仅用于观察依赖覆盖范围,客户端可以任意伪造,不能用于真实管理员判定。实际角色应在验证令牌后从服务端可信用户资料中读取,第 36 篇介绍认证基础。
两个配置位置有什么区别
在 APIRouter(dependencies=...) 设置,代表路由自身的共同要求;在 app.include_router(router, dependencies=...) 设置,代表这次挂载额外附加的要求。模块路由被不同应用复用时,后者更灵活。
依赖是叠加而不是覆盖:全局要求、路由要求、单操作要求都会参与执行。想为某一条操作取消路由级认证,通常应把它拆到独立的公开路由集合,而不是在函数里试图跳过已经执行的依赖。
返回值和组织方式
路由级依赖的返回值也不会自动注入函数。需要当前用户时,在具体函数中声明同一用户依赖;同一请求通常可复用缓存结果。认证、角色检查可以按嵌套依赖组织,避免重复解码令牌。
业务 tags、路径前缀都只是组织手段,没有默认的安全效果;真正控制权限的是执行的认证和授权逻辑。
练习:把 /admin/reports 拆到单独的只读路由,给它增加另一项依赖;列出每个最终 URL 会执行哪些检查。