FastAPI 作为现代化的 Python Web 框架,提供了开箱即用的安全认证组件,覆盖从简单的 API 密钥到复杂的 OAuth2 授权码流、JWT 认证等全场景。本系列教程将系统梳理 FastAPI 支持的所有认证方式,结合实战代码与最佳实践,帮助你根据业务场景选择最合适的认证方案。

前言:为什么接口必须做认证

在实际开发中,接口认证是后端服务的第一道安全防线,核心作用是:

  1. 身份校验:确认调用接口的用户 / 服务是合法的,拒绝非法访问;
  2. 权限控制:防止未授权用户操作敏感数据(如用户信息、订单、管理后台接口);
  3. 日志追溯:通过认证信息定位接口调用者,便于问题排查;
  4. 合规要求:满足数据安全规范(如隐私数据保护、企业安全标准)。

如果没有认证,你的接口会直接暴露在公网,任何人都能随意调用,极易导致数据泄露、恶意攻击、服务滥用等严重问题。

一、核心概念:认证与授权

很多新手会混淆认证(Authentication)和授权(Authorization),这是安全开发的基础概念:

  • 认证(Authentication):验证**“你是谁”**→ 验证身份的合法性,常见方式包括账号密码、API 密钥、Token、第三方登录等。
  • 授权(Authorization)你能做什么 → 基于认证后的身份验证是否有操作权限(比如:普通用户不能删除数据、管理员才能访问后台)。

本文重点讲认证(身份校验),后续篇章会讲解授权结合使用。

二、FastAPI 安全架构

FastAPI 认证核心工具(Depends / Security)

FastAPI 基于 Python 标准库和自身特性,提供了两个认证核心工具,所有认证方式都依赖它们实现:

Depends(依赖注入)

Depends 是 FastAPI 最核心的功能,用于提取公共逻辑、复用代码,认证逻辑本质就是「所有接口都需要执行的身份校验」,完美适配依赖注入。

  • 作用:把认证逻辑封装成函数,所有接口通过 Depends 自动调用,无需重复写校验代码;
  • 特性:支持全局、路由、单接口三级注入,灵活控制认证范围。
Security(安全工具)

fastapi.security 是 FastAPI 专门封装的认证工具包,内置了 API Key 等标准认证方案,遵循 OpenAPI 规范,自动生成交互式文档的认证入口。

  • 核心类:APIKeyQuery/APIKeyHeader/APIKeyCookie
  • 特性:自动适配 Swagger UI 文档,支持一键填入认证信息测试接口。

FastAPI 认证方式

FastAPI 认证方式分为基础认证类OAuth2 认证类两大体系:

组件类型核心类适用场景
基础认证APIKeyHeader/APIKeyQuery/APIKeyCookie简单 API 密钥认证、Swagger 手动输入 Token
基础认证HTTPBasic/HTTPBearer基础账号密码认证、标准 Bearer Token 认证
OAuth2 认证OAuth2Password``Bearer自身系统的账号密码登录、JWT 签发
OAuth2 认证OAuth2AuthorizationCodeBearer第三方登录(GitHub、Gitee、微信、支付宝)
OAuth2 认证OAuth2ClientCredentials服务间调用(客户端凭证模式)

三、API Key 认证原理

API Key 是一串预生成的唯一字符串(类似「接口密钥」),是服务端和客户端约定的身份凭证,属于最简单、最常用的无状态认证方式

认证流程如下:

  1. 服务端提前给合法客户端分配一个固定的 API Key(存储在配置文件 / 数据库);
  2. 客户端调用接口时,必须携带这个 API Key;
  3. 服务端拦截请求,提取 API Key 并与本地存储的凭证对比;
  4. 校验通过 → 放行请求;校验失败 → 直接返回 401 错误。

在这里插入图片描述

四、API Key 三种传递方式:Header / Query / Cookie

FastAPI 在 fastapi.security 中提供了三个开箱即用的 API Key 认证类,分别对应三种不同的 API Key 传递方式:

类名获取位置示例推荐度
APIKeyHeader请求头(Header)X-API-KEY: abc123⭐⭐⭐⭐⭐(最常用、最安全)
APIKeyQueryURL 查询参数/api/user?token=abc123⭐⭐(会暴露在 URL 日志)
APIKeyCookieCookieCookie: token=abc123⭐⭐⭐(适合 Web 前端)

三者用法几乎完全一样,仅获取密钥的位置不同。

APIKeyHeader(Header 请求头)

APIKeyHeader 是 FastAPI 官方推荐、企业最常用的 API Key 认证方式,从 HTTP 请求头(Header)中提取密钥,安全性最高、最符合接口规范,自动对接 Swagger 文档。

配置参数
APIKeyHeader(
    name: str,                # 请求头的 key 名称(必须)
    scheme_name: str = None,  # OpenAPI 文档显示的安全方案名
    description: str = None,  # 文档描述
    auto_error: bool = True   # 未传密钥时是否自动返回 401
)
代码示例
  1. 使用 APIKeyHeader 定义全局通用的 API Key 提取器,从自定义请求头 X-API-Key 中获取密钥:

    from fastapi.security import APIKeyHeader
    # 从请求头 X-API-Key 提取密钥
    api_key_header = APIKeyHeader(name="X-API-Key")
    

    name 用于告诉 FastAPI 从请求头的哪个字段获取 API Key(常用:X-API-KeyX-Token),即name="X-API-Key" 要求客户端必须在请求头中携带 X-API-Key 字段才能访问受保护接口。

  2. 编写接口/api/user/info,通过 Depends(api_key_header) 注入认证依赖,接口会先执行密钥校验,校验通过后才会执行业务逻辑:

    @app.get("/api/user/info", summary="需要 API Key 才能访问")
    def get_user_info(api_key: str = Depends(api_key_header)):
        return {
            "code": 200,
            "msg": "获取用户信息成功",
            "api_key": api_key[:6] + "****"  # 脱敏展示
        }
    

    接收到请求后,FastAPI 会先执行 api_key_headerapi_key_header会自动从请求头里找 X-API-Key

    1. 如果没有 X-API-Key 请求头 → 直接返回 401,接口代码不执行
    2. 如果 → 把密钥取出来,赋值给参数 api_key
  3. 编写公开接口(无需任何认证),所有人可直接访问:

    @app.get("/api/public/hello", summary="公开接口,无需认证")
    def public_hello():
        return {
            "code": 200,
            "msg": "Hello, 公开接口"
        }
    
  4. 启动应用:uvicorn main:app --reload,访问 Swagger 文档:http://127.0.0.1:8000/docs

    在这里插入图片描述

  5. 点击右上角 Authorize 按钮:

    在这里插入图片描述

  6. 输入合法的 API 密钥(如 sk_123456),点击授权:

    在这里插入图片描述

  7. 之后访问所有接口会**自动携带****X-API-Key**请求头,访问受保护接口时可正常获取数据;未授权则会抛异常:

    在这里插入图片描述

APIKeyQuery(URL 参数)

APIKeyQuery 是 FastAPI 提供的 API Key 认证工具,用法与 APIKeyHeader 完全一致,仅密钥提取位置不同:它从 URL 查询参数 中提取 API Key,适合临时接口调试、内部简易接口场景。

配置参数
APIKeyQuery(
    name: str,               # 必填:URL 查询参数的键名(客户端需拼接 ?参数名=密钥)
    scheme_name: str = None, # 可选:自定义认证方案名称(用于接口文档展示)
    description: str = None, # 可选:认证方案描述(用于接口文档说明)
    auto_error: bool = True  # 可选:自动抛出异常,默认True(未携带密钥直接返回401)
)
代码示例
  1. 定义 APIKeyQuery 提取规则:

    from fastapi.security import APIKeyQuery
    # 定义查询参数的 key 名称(客户端URL拼接 ?token=你的APIKey)
    api_key_query = APIKeyQuery(name="token", auto_error=False)
    

    name="api_key" 告诉 FastAPI 从 URL 参数 api_key 中获取密钥

  2. 编写测试接口,其中 /api/data 接口只有带正确 URL 参数的请求才能访问:

    @app.get("/api/data", summary="URL 参数带 API Key")
    def get_data(api_key: str = Depends(api_key_query)):
        return {"code": 200, "msg": "通过 URL 参数认证成功"}
        
    @app.get("/api/public")
    def public_api():
        return {"msg": "公开接口,无需 URL 参数"}
    

    FastApi 接收到请求后,Depends(api_key_query) 先检查 URL 里有没有 ?api_key=xxx

    1. 没有参数 → 直接 403,接口不运行
    2. 有参数 → 取出值赋值给 api_key,接口执行

APIKeyCookie(Cookie 提取)

APIKeyCookie 用于从请求 Cookie 中提取 API Key,是前后端一体 Web 项目的常用认证方式,浏览器会自动携带 Cookie 完成认证。

配置参数
APIKeyCookie(
    name: str,               # 必填:Cookie 的键名(客户端需携带 Cookie:键名=密钥)
    scheme_name: str = None, # 可选:自定义认证方案名称(接口文档展示)
    description: str = None, # 可选:认证方案描述(接口文档说明)
    auto_error: bool = True  # 可选:自动抛出异常,默认True(无Cookie直接返回401)
)
代码示例
  1. 定义提取规则,指定从 Cookie 字段 token 中取密钥:

    from fastapi.security import APIKeyCookie
    # 定义:从 Cookie 的 token 字段中提取 API Key 
    api_key_cookie = APIKeyCookie(name="token",auto_error=False)
    
  2. 编写受保护接口,依赖注入Depends(api_key_cookie)

    @app.get("/api/user/profile", summary="从 Cookie 取 API Key")
    def get_profile(api_key: str = Depends(api_key_cookie)):
        return {"code": 200, "msg": "通过 Cookie 认证成功"}
    

    请求到达接口时,Depends(api_key_cookie) 优先校验请求中是否携带 token=xxxCookie:

    1. token=xxx Cookie → 直接返回 401,拒绝访问;
    2. 携带有效 Cookie → 自动提取密钥,赋值给 api_key 变量,接口放行。

五、认证范围配置

FastAPI 认证支持三种灵活配置

  1. 全局认证(所有接口默认需要认证)
  2. 路由分组认证(某一组接口统一认证,例如 /api/*
  3. 单接口认证(仅某个接口需要认证)

全局认证(全接口生效)

该方式项目所有接口开启认证,无需为每个接口单独配置,适用于全接口鉴权场景:

app = FastAPI(dependencies=[Depends(verify_api_key)])

路由分组认证(指定前缀生效)

使用 APIRouter某一类接口统一加认证,该路由下的所有接口开启认证,其他路由接口不受影响

from fastapi import APIRouter

# 创建需要认证的路由
api_router = APIRouter(dependencies=[Depends(verify_api_key)])

# 该路由下所有接口自动认证
@api_router.get("/user/list")
async def user_list():
    return {"msg": "该接口已自动通过API Key认证"}

# 把路由注册到 app
app.include_router(api_router, prefix="/api")

单接口认证(独立生效)

直接在接口上加依赖,仅当前接口生效:

@app.get("/order/info", dependencies=[Depends(verify_api_key)])
async def order_info():
    return {"msg": "仅该接口需要认证"}
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐