---
title: FastAPIdependency-injection完全指南 - 代码复用与权限校验最佳实践 | 道满PythonAI
description: 深入掌握FastAPI依赖注入核心机制,实现代码复用、权限校验与数据库连接。包含实战示例、依赖链构建及企业级应用模式。
keywords: [FastAPI, 依赖注入, DI, 代码复用, 权限校验, 数据库连接, Depends, 认证系统, 中间件]
date: 2026-04-10
updated: 2024-01-15
author: 道满PythonAI
tags: [FastAPI, 依赖注入, 认证授权, 企业级开发]
---

# FastAPIdependency-injection完全指南

> 📂 所属阶段:第二阶段 — 进阶黑科技(核心篇)  
> 🔗 相关章节:[FastAPI异步编程深度解析](/pyweb/fastapi/async-await-principles) · [FastAPImiddleware-application](/pyweb/fastapi/middleware-application)

依赖注入(Dependency Injection)是 FastAPI 最吸引人的特性之一。它让你用**声明式**的方式告诉系统“我需要什么”,而不再重复编写那些散落在各处的样板代码。本文将带你从零开始,掌握依赖注入的各类用法,并构建一套可重用的认证授权体系。

## 目录
- [什么是依赖注入?](#什么是依赖注入)
- [基础用法](#基础用法)
- [数据库连接与依赖](#数据库连接与依赖)
- [依赖链与级联](#依赖链与级联)
- [可选依赖与默认值](#可选依赖与默认值)
- [依赖缓存机制](#依赖缓存机制)
- [实战:认证授权体系](#实战认证授权体系)
- [进阶用法](#进阶用法)
- [避坑指南与性能优化](#避坑指南与性能优化)
- [总结](#总结)

---

## 什么是依赖注入?

### 不用依赖注入的痛点
假设我们需要在多个路由中做用户认证,一种很自然的写法是直接把认证逻辑粘贴进去:

```python
# ❌ 没有依赖注入:重复逻辑散落在每个路由
from fastapi import FastAPI, HTTPException, Request
from db import fake_db

app = FastAPI()

@app.get("/users/me")
def get_current_user(request: Request):
    token = request.headers.get("Authorization")
    if not token or not token.startswith("Bearer "):
        raise HTTPException(401, "Unauthorized")
    user = fake_db.get_user(token.replace("Bearer ", ""))
    if not user:
        raise HTTPException(401, "Invalid token")
    return user

@app.get("/orders")
def get_orders(request: Request):
    token = request.headers.get("Authorization")
    # 重复的认证逻辑!
    if not token or not token.startswith("Bearer "):
        raise HTTPException(401, "Unauthorized")
    user = fake_db.get_user(token.replace("Bearer ", ""))
    if not user:
        raise HTTPException(401, "Invalid token")
    return fake_db.get_orders(user["id"])

核心问题:代码复用率低、修改成本高、可测试性差。一旦认证规则变化,你需要手动修改每个路由函数。

用依赖注入解决

FastAPI 通过 Depends 让路由声明式地表达自己的需求。你把公共逻辑抽成一个函数,然后让需要的路由“依赖”它:

# ✅ 依赖注入:抽成公共依赖,按需注入
from fastapi import Depends, Header, HTTPException

# 1. 抽成公共认证依赖
async def get_current_user(
    authorization: str = Header(...)
) -> dict:
    if not authorization.startswith("Bearer "):
        raise HTTPException(401, "Invalid token format")
    token = authorization.replace("Bearer ", "")
    user = fake_db.get_user(token)
    if not user:
        raise HTTPException(401, "Invalid token")
    return user

# 2. 路由只需声明需要的依赖
@app.get("/users/me")
async def get_me(user: dict = Depends(get_current_user)):
    return user

@app.get("/orders")
async def get_orders(user: dict = Depends(get_current_user)):
    return fake_db.get_orders(user["id"])

现在业务逻辑一目了然,路由只负责返回数据,认证细节全部交给依赖处理。

核心优势

  1. 代码复用:公共逻辑只需定义一次
  2. 解耦清晰:路由只关注业务逻辑
  3. 可测试性强:依赖可轻松替换为模拟对象
  4. 维护成本低:修改一处即可全局生效
  5. 内置优化:请求级缓存避免重复执行(后文细讲)

基础用法

1. Depends 函数详解

Depends(可调用对象) 是核心——你可以传入普通函数、异步函数、类甚至生成器。FastAPI 会自动分析依赖的参数并注入相应的请求数据。

# 普通函数依赖:处理查询参数
def get_search_query(q: str = "default"):
    return f"搜索内容: {q}"

@app.get("/search")
async def search(q: str = Depends(get_search_query)):
    return {"result": q}

当访问 /search?q=fastapi 时,依赖会自动获取 q 的值并传入路由。

2. 带 Query/Path 的依赖工厂

依赖的参数也可以使用 FastAPI 的验证工具(如 QueryPath),构建更强大的依赖工厂

from fastapi import Query

# 分页依赖工厂
def pagination(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(10, ge=1, le=100, description="每页条数")
):
    return {"page": page, "page_size": page_size}

@app.get("/items")
async def list_items(p: dict = Depends(pagination)):
    # 自动解析并验证参数
    return {"data": ["item1", "item2"], "pagination": p}

这样所有需要分页的路由都可以复用这段验证逻辑,同时自动获得了 API 文档中的参数说明。

3. 类作为依赖

当逻辑稍复杂时,可以使用类作为依赖。FastAPI 会自动调用 __init__ 实例化,让你可以封装多个方法和状态:

class AuthService:
    def __init__(self, authorization: str = Header(...)):
        self.token = authorization.replace("Bearer ", "")
        self.user = self._verify()

    def _verify(self):
        if self.token == "admin123":
            return {"id": 1, "role": "admin"}
        elif self.token == "user456":
            return {"id": 2, "role": "user"}
        raise HTTPException(401, "Invalid token")

@app.get("/profile")
async def get_profile(auth: AuthService = Depends()):
    # 类实例直接使用,简洁直观
    return auth.user

⚠️ 注意:当依赖是类时,Depends() 不需要传入类名,因为 FastAPI 会自行推断。


数据库连接与依赖

依赖注入非常适合管理数据库连接——请求开始时获取会话,请求结束后自动释放。

异步 SQLAlchemy 依赖示例

利用 yield 可以实现资源的优雅管理:

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker

# 配置连接池
DATABASE_URL = "sqlite+aiosqlite:///./app.db"
async_engine = create_async_engine(
    DATABASE_URL,
    pool_size=20,
    max_overflow=30,
    pool_pre_ping=True
)
AsyncSessionLocal = sessionmaker(
    async_engine, class_=AsyncSession, expire_on_commit=False
)

# 数据库依赖
async def get_db() -> AsyncSession:
    async with AsyncSessionLocal() as session:
        try:
            yield session
        except Exception:
            await session.rollback()
            raise
        else:
            await session.commit()

# 使用方式
@app.get("/users/{user_id}")
async def get_user(
    user_id: int,
    db: AsyncSession = Depends(get_db)
):
    from sqlalchemy import select
    from models import User
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(404, "User not found")
    return user

请求期间,yield 之前的代码负责创建会话并注入路由;请求结束后,yield 之后的代码负责提交事务或回滚。整个过程对业务代码透明。


依赖链与级联

依赖可以嵌套其他依赖,形成清晰的依赖链,每一层只做好自己的事。

三层认证授权依赖链示例

# 第一层:提取并清理 Token
def get_token(authorization: str = Header(...)):
    if not authorization.startswith("Bearer "):
        raise HTTPException(401, "Invalid token format")
    return authorization.replace("Bearer ", "")

# 第二层:根据 Token 验证用户(依赖第一层)
def get_current_user(token: str = Depends(get_token)):
    user = fake_db.get_user(token)
    if not user:
        raise HTTPException(401, "Invalid token")
    return user

# 第三层:检查管理员权限(依赖第二层)
def require_admin(current_user: dict = Depends(get_current_user)):
    if current_user["role"] != "admin":
        raise HTTPException(403, "Admin access required")
    return current_user

# 使用依赖链
@app.get("/admin/dashboard")
async def admin_dashboard(admin: dict = Depends(require_admin)):
    return {"admin": admin}

顺序非常直观:require_admin 依赖 get_current_user,而 get_current_user 又依赖 get_token。每一层只处理自己关心的问题,组合起来就构建出强大的权限控制。


可选依赖与默认值

有些场景下,用户可能登录也可能未登录,此时可以通过 Optional 创建可选依赖

from typing import Optional

# 可选认证依赖
async def get_optional_user(
    authorization: Optional[str] = Header(None)
) -> Optional[dict]:
    if not authorization:
        return None
    return fake_db.get_user(authorization.replace("Bearer ", ""))

# 公开接口,有用户信息返回个性化内容,否则返回通用内容
@app.get("/home")
async def home(user: Optional[dict] = Depends(get_optional_user)):
    if user:
        return {"message": f"Welcome back, {user['name']}!"}
    return {"message": "Welcome, guest!"}

当请求携带 Authorization 头时,依赖返回用户对象;否则返回 None。路由根据结果提供不同体验,既灵活又安全。


依赖缓存机制

1. 默认请求级缓存

在同一个请求中,如果多个路由或依赖链都使用了同一个依赖,FastAPI 默认只会执行一次,结果会被缓存复用。这可以避免重复查询数据库或进行重复计算。

def get_user():
    print("🔍 查询用户(只打印一次)")
    return {"id": 1, "name": "Alice"}

@app.get("/a")
@app.get("/b")
async def endpoints(user: dict = Depends(get_user)):
    return {"user": user}

即使 /a/b 被同时调用(或者一个请求中多次调用),你也只会看到一次打印。这就是缓存带来的性能优化。

2. 禁用缓存:use_cache=False

但如果你的依赖需要每次返回不同结果(例如生成 UUID 或读取实时数据),可以通过 use_cache=False 关闭缓存:

import uuid

def get_request_id():
    return str(uuid.uuid4())

@app.get("/uuid")
async def get_uuid(
    req_id1: str = Depends(get_request_id, use_cache=False),
    req_id2: str = Depends(get_request_id, use_cache=False)
):
    # req_id1 和 req_id2 会不同
    return {"req_id1": req_id1, "req_id2": req_id2}

此时两个参数会分别调用依赖,获得各自独立的 UUID。


实战:认证授权体系

下面我们用依赖注入构建一个可组合、可扩展的认证授权体系。

依赖分层设计

请求 → 中间件(可选) → 依赖注入链

         1. get_db          (数据库连接)
         2. get_token       (提取 Token)
         3. get_current_user(验证用户)
         4. require_roles   (角色检查)

             路由处理器

核心代码示例

# auth_dependencies.py
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from typing import List

security = HTTPBearer(auto_error=False)

def decode_token(token: str) -> dict:
    # 模拟 JWT 验证
    if token == "admin":
        return {"id": 1, "role": "admin", "sub": "admin@example.com"}
    elif token == "editor":
        return {"id": 2, "role": "editor", "sub": "editor@example.com"}
    raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Invalid token")

def require_roles(allowed_roles: List[str]):
    """角色权限检查工厂函数"""
    async def checker(
        cred: HTTPAuthorizationCredentials = Depends(security)
    ) -> dict:
        user = decode_token(cred.credentials)
        if user["role"] not in allowed_roles:
            raise HTTPException(status.HTTP_403_FORBIDDEN, "Permission denied")
        return user
    return checker

# 预定义常用角色依赖
require_admin = require_roles(["admin"])
require_editor = require_roles(["admin", "editor"])
# main.py
from fastapi import FastAPI, Depends
from auth_dependencies import require_admin, require_editor

app = FastAPI()

@app.get("/public")
async def public():
    return {"status": "ok"}

@app.get("/me")
async def me(user: dict = Depends(require_editor)):
    return user

@app.delete("/users/{user_id}")
async def delete_user(user_id: int, _: dict = Depends(require_admin)):
    # 下划线表示不需要使用返回值
    return {"deleted": user_id}

这种设计让你可以像搭积木一样组合权限:只需要改变 require_roles 的参数,就能复用同一套认证逻辑。


进阶用法

1. 全局路由级依赖

APIRouterinclude_router 中添加 dependencies,可以实现一组路由共用前置依赖,非常适合为整个模块添加权限保护:

from fastapi import APIRouter

admin_router = APIRouter(
    prefix="/admin",
    dependencies=[Depends(require_admin)]  # 所有 admin 路由都需要管理员权限
)

@admin_router.get("/users")
async def list_admin_users():
    return {"users": ["admin1"]}

app.include_router(admin_router)

在这里,你不需要在每个路由中重复添加依赖,整个子模块的访问控制由框架统一管理。


避坑指南与性能优化

避坑指南

  1. 避免副作用:依赖函数应保持幂等,尽量不修改全局状态。
  2. 避免循环依赖:不要让 A 依赖 B,而 B 又依赖 A。
  3. 避免过度嵌套:依赖链深度一般不超过 3-4 层,否则调试困难。
  4. 避免异步依赖中的阻塞操作:如果依赖中有 IO 密集型或 CPU 密集型代码,应使用 run_in_threadpool 或相关工具移至线程池。

性能优化

  1. 善用默认请求级缓存:减少重复的数据库查询或计算。
  2. 配置合理的数据库连接池:避免连接耗尽,如上文中 pool_sizemax_overflow 的设置。
  3. 依赖执行顺序优化:把最可能快速失败的验证放在依赖链前面(如 Token 格式检查),让请求尽早返回,节省资源。

总结

模式说明适用场景
Depends(func)基础依赖注入参数提取、简单验证
Depends(Class)类依赖服务类、复杂逻辑
依赖链嵌套依赖认证→用户→权限
use_cache=False禁用缓存实时数据、随机数
全局 dependencies路由组依赖权限控制分组

💡 核心思想:依赖注入让代码变得可测试、可复用、声明式、易维护,是构建企业级 FastAPI 应用的核心工具。


🔗 官方扩展阅读