行业资讯
📅 2026/9/8 20:22:48
FastAPI 获取当前用户:基于 OAuth2 Bearer Token 与依赖注入的实战指南
FastAPI 获取当前用户基于 OAuth2 Bearer Token 与依赖注入的实战指南【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi导读在 FastAPI 的安全体系中拿到一个 token 字符串只是第一步。要让每个受保护的路由能直接拿到当前登录用户需要把 token 解析、用户查询与校验封装成可复用的依赖dependency。本文基于 FastAPI 官方文档 docs/hi/docs/tutorial/security/get-current-user.md与英文原文同结构展开结合仓库中的示例源码与测试用例完整讲解如何用 Pydantic 定义用户模型、编写带子依赖的get_current_user并通过Depends把当前用户注入到path operation中。读完你将掌握一套一次编写、全端点复用的安全注入模式。前置知识上一章留下的 token在继续之前需要回顾上一个章节 security/first-steps 中建立的oauth2_scheme。它基于OAuth2PasswordBearer实现会把请求Authorization头中Bearer前缀之后的 token 作为str返回给调用方。上一章的完整代码见 docs_src/security/tutorial001_an_py310.pyfrom typing import Annotated from fastapi import Depends, FastAPI from fastapi.security import OAuth2PasswordBearer app FastAPI() oauth2_scheme OAuth2PasswordBearer(tokenUrltoken) app.get(/items/) async def read_items(token: Annotated[str, Depends(oauth2_scheme)]): return {token: token}问题在于read_items拿到的只是原始 token 字符串{token: token}对业务来说还不是那么有用。本文要做的就是把这条链路升级为直接返回当前登录用户对象。顺带理解oauth2_scheme为什么能直接放进Depends查看 fastapi/security/oauth2.py 可知OAuth2PasswordBearer继承自OAuth2OAuth2又继承自 fastapi/security/base.py 中的SecurityBase且类内部定义了可调用的async def __call__(self, request: Request)。因此它既是一个可调用对象也是一个合法的依赖。FastAPI 正是依据SecurityBase这一基类识别出这些安全工具可以集成到 OpenAPI及/docs交互文档的安全方案声明中。第一步定义 Pydantic 用户模型既然目的是把用户交给业务代码就需要先有一个描述用户形状的数据模型。与声明请求体request body一样FastAPI 官方推荐使用 PydanticBaseModel而且在任何需要的地方都可以这样用——不仅限于请求体。示例见 docs_src/security/tutorial002_an_py310.pyfrom typing import Annotated from fastapi import Depends, FastAPI from fastapi.security import OAuth2PasswordBearer from pydantic import BaseModel app FastAPI() oauth2_scheme OAuth2PasswordBearer(tokenUrltoken) class User(BaseModel): username: str email: str | None None full_name: str | None None disabled: bool | None None字段含义说明username必填字符串用户的唯一标识email、full_name、disabled均为可选项。email与full_name缺省为Nonedisabled用于后续章节演示禁用账号校验场景可参考 security/simple-oauth2 中如何基于该字段拦截请求。在本章这个模型主要用于演示从 token 解码出用户数据的载体。真实项目里User可能是从数据库查询出的 ORM 实例、dataclass 或任何自定义类——Pydantic 模型只是当前教程选用的形式绝非唯一形式。第二步编写get_current_user依赖FastAPI 的依赖系统允许依赖再嵌套依赖即子依赖sub-dependencies。我们让get_current_user声明一个与oauth2_scheme的子依赖关系由oauth2_scheme负责从请求头解析出str类型的 token再把它交给get_current_user。这与上一章直接在path operation里Depends(oauth2_scheme)的做法如出一辙只是把消费方从路由函数下沉到了依赖内部async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): user fake_decode_token(token) return user这里用到的fake_decode_token是一个仅供演示的假工具函数——它接收str形式的 token返回一个User模型实例真实场景中对应解析 token → 查询数据库 → 构造用户的整条逻辑def fake_decode_token(token): return User( usernametoken fakedecoded, emailjohnexample.com, full_nameJohn Doe )底层机制没有 token 会怎样你可能关心如果请求头里根本没有Authorization或格式不对get_current_user会如何执行答案在oauth2_scheme内部已经兜底。查看 fastapi/security/oauth2.py 中OAuth2PasswordBearer.__call__的实现读取request.headers.get(Authorization)通过get_authorization_scheme_param拆出 scheme 与参数若缺少该头或 scheme 不是bearer默认auto_errorTrue直接抛出 401 HTTPException错误信息为Not authenticated并附带WWW-Authenticate: Bearer响应头见make_not_authenticated_errorfastapi/security/oauth2.py只有通过校验时才会把Bearer之后的 token 字符串继续向上返回。因此只要你的get_current_user函数能被执行到token就必然是一个有效的str无需在依赖内重复做token 是否为空的判断。OAuth2PasswordBearer构造函数还接受auto_errorFalse等参数用于实现可选认证等进阶场景详见 fastapi/security/oauth2.py。第三步把当前用户注入path operation现在可以回到路由层。与之前Depends(oauth2_scheme)的使用方式完全相同只要把依赖换成get_current_userFastAPI 就会自动完成整条依赖链的解析oauth2_scheme→get_current_user→ 路由函数app.get(/users/me) async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]): return current_user注意current_user的类型被声明为 Pydantic 模型User。这一步非常关键编辑器与 IDE 会在函数体内提供完整的代码补全与类型检查后续调用current_user.username、current_user.email等属性时静态检查工具可以即时发现拼写错误。为什么 FastAPI 不会把User误当作请求体一个常见的困惑是Pydantic 模型既用于声明请求体又用于依赖返回值FastAPI 如何区分答案就在Depends上。一旦参数被Depends(...)或Security(...)包裹FastAPI 就明确知道该参数来自依赖注入系统而不是请求体。依赖注入Dependency Injection层次的解析逻辑集中在 fastapi/dependencies/utils.py它会递归求解每个参数的子依赖而不再把参数当作 body / query / path 等请求参数处理。这也是整个教程反复强调的设计精髓。完整示例一览把上述代码合并就是本章的完整可运行示例 docs_src/security/tutorial002_an_py310.pyfrom typing import Annotated from fastapi import Depends, FastAPI from fastapi.security import OAuth2PasswordBearer from pydantic import BaseModel app FastAPI() oauth2_scheme OAuth2PasswordBearer(tokenUrltoken) class User(BaseModel): username: str email: str | None None full_name: str | None None disabled: bool | None None def fake_decode_token(token): return User( usernametoken fakedecoded, emailjohnexample.com, full_nameJohn Doe ) async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): user fake_decode_token(token) return user app.get(/users/me) async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]): return current_user仓库中还存在一份不使用Annotated、而直接把默认值写成current_user: User Depends(get_current_user)风格的变体 docs_src/security/tutorial002_py310.py。两者行为等价Annotated是 FastAPI 目前推荐、也更利于类型可读性的写法。行为验证测试用例怎么说仓库测试 tests/test_tutorial/test_security/test_tutorial002.py 精确刻画了上述端点的三种行为无 token 请求GET /users/me→ 返回401body 为{detail: Not authenticated}响应头带WWW-Authenticate: Bearer——印证了OAuth2PasswordBearer的自动拦截携带有效头GET /users/meheader 为Authorization: Bearer testtoken→ 返回200响应体为{username: testtokenfakedecoded, email: johnexample.com, full_name: John Doe, disabled: null}——可见 tokentesttoken经fake_decode_token变成了usernameOpenAPI schema 检查GET /openapi.json→ 路由/users/me的security声明为[{OAuth2PasswordBearer: []}]components.securitySchemes中生成oauth2类型、flows.password.tokenUrl为token。这证明即使业务依赖换成了get_current_userFastAPI 仍能沿着依赖链识别出OAuth2PasswordBearer并把安全方案写入自动文档。这意味着无需任何手写/docs交互界面会自动为该路由显示 Authorize 按钮与鉴权标识。返回值类型不限依赖系统的高度灵活性需要特别强调依赖系统的设计使你可以拥有多个不同的可依赖项dependables只要它们都返回User模型就不会互相冲突。你不受只有一个依赖能返回某类型数据的限制。更进一步返回的数据形态完全由你的业务决定想用包含id、email而没有username的模型完全可以工具不变只想返回一个str或dict没问题想直接返回数据库的类模型实例如 SQLAlchemy 实体同样可行登录方根本不是人类用户而是持有 access token 的机器人、爬虫或第三方系统依旧同一套流程。结论是无论你的应用需要何种模型、何种类、何种数据库FastAPI 的依赖注入系统都能满足。安全机制停留在依赖注入层面业务模型则保持完全自由。这与官方文档 Other models 一节的观点一致。代码量权衡安全逻辑只写一次有读者会觉得上述示例略显冗长——因为它把安全声明、数据模型、工具函数和path operation全部塞进了同一个文件。但请抓住核心要点安全与依赖注入相关的逻辑只需编写一次无论你把它做得多么复杂它始终集中在一个位置且拥有全部灵活性之后你的应用可以拥有成千上万个使用同一安全体系的端点这些端点或其任意子集都能复用get_current_user或复用它内部依赖的其它任意依赖每个受保护端点的代码可以精简到 3 行左右app.get(/users/me) async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]): return current_user当你的鉴权需求日后升级——比如接入真实数据库、加入账号禁用判断、签发 JWT——只需改动get_current_user及其子依赖这一处所有端点同步生效。这正是把安全机制提升到依赖注入层带来的可维护性红利。小结与下一步到此为止你已能在path operation function中直接取得current_user一个 PydanticUser实例token 的解析、缺失时的 401 拦截、用户的解码与构造全部由依赖链oauth2_scheme → get_current_user自动完成安全逻辑与业务逻辑通过Depends清晰解耦。教程进度到这里大约走了一半。目前还缺最后一块拼图让用户/客户端真正把username与password发送过来并换取 token的path operation即tokenUrltoken指向的端点。相关内容见下一篇 security/simple-oauth2更完整的账号/密码校验流程以及在此之上引入签名令牌的 security/oauth2-jwt。若想了解比Depends更强的Security与 scopes 用法可进一步研读 fastapi/security/oauth2.py 中SecurityScopes的实现以及仓库中 tests/test_security_scopes_sub_dependency.py 对应的测试。附相关仓库文件索引教程源码Annotated 风格docs_src/security/tutorial002_an_py310.py上一章基础示例docs_src/security/tutorial001_an_py310.py本章行为测试tests/test_tutorial/test_security/test_tutorial002.py安全工具实现fastapi/security/oauth2.py、fastapi/security/base.py依赖注入核心解析器fastapi/dependencies/utils.py印地语教程目录入口docs/hi/docs/tutorial/security/index.md【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考