← 返回题目列表

FastAPI 中如何实现认证和授权?

高频 中等 第 13 / 27 题 更新于 2026/07/27
认证授权JWTOAuth2Depends

简化版

FastAPI 通常用依赖注入实现认证和授权:先从请求头解析 token,验证 token 后得到当前用户,再在依赖或业务层检查权限。认证回答“你是谁”,授权回答“你能做什么”,两者要分清。

详细版

FastAPI 提供了安全工具,例如 OAuth2PasswordBearer,可以帮助从 Authorization: Bearer <token> 中提取 token。实际项目中常见流程是:

  1. 登录接口校验用户名密码;
  2. 生成 JWT 或服务端 session token;
  3. 受保护接口通过 Depends 获取当前用户;
  4. 权限依赖检查角色、权限点、资源归属;
  5. 认证失败返回 401,权限不足返回 403。

示例:

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/login")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    payload = verify_jwt(token)
    return get_user(payload["sub"])

def require_admin(user: User = Depends(get_current_user)):
    if not user.is_admin:
        raise HTTPException(status_code=403, detail="权限不足")
    return user

完整版教学

一、认证和授权必须分开讲

认证和授权是面试里非常容易混淆的两个概念。

认证是 Authentication,回答“请求者是谁”。比如用户提供用户名密码登录,系统验证成功后签发 token。后续请求带上 token,服务端解析 token 得到用户身份。

授权是 Authorization,回答“这个用户能不能做这件事”。比如普通用户可以查看自己的订单,但不能删除其他用户,也不能访问后台管理接口。

一个用户认证成功,不代表他拥有所有权限。所以面试回答不能只说“用 JWT 就实现权限了”。JWT 主要解决身份携带和验证,权限判断还要结合角色、权限点、资源归属等业务规则。

二、FastAPI 为什么适合用 Depends 做认证

认证逻辑几乎是典型的请求级依赖:某些接口需要当前用户,某些接口不需要;不同接口可能需要不同权限。FastAPI 的 Depends 很适合表达这种关系。

常见写法是:

from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/login")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    payload = verify_token(token)
    if payload is None:
        raise HTTPException(status_code=401, detail="认证失败")
    user = get_user_by_id(payload["sub"])
    if user is None:
        raise HTTPException(status_code=401, detail="用户不存在")
    return user

业务接口只需要声明依赖:

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

这样路由函数就不用关心 token 从哪里来、如何解析、失败怎么响应。

三、JWT 的基本流程

JWT 是无状态 token 的常见选择。登录成功后,服务端把用户标识、过期时间等信息编码到 token 中,并用密钥签名。客户端后续请求在 Authorization 头中携带:

Authorization: Bearer eyJhbGciOi...

服务端收到请求后验证签名、检查过期时间、读取用户标识。因为 JWT 本身包含信息,服务端不一定需要查询 session 存储,这对分布式部署比较友好。

但 JWT 也有代价。已签发 token 在过期前通常难以主动失效,除非引入黑名单、token 版本号、短期 access token + refresh token 等机制。因此生产系统需要认真设计 token 过期时间、刷新机制和撤销策略。

四、OAuth2PasswordBearer 的作用边界

OAuth2PasswordBearer 容易被误解。它并不会自动帮你完成登录、加密密码、生成 JWT、校验用户。它主要做两件事:告诉 OpenAPI 文档这个接口使用 Bearer token;从请求头中提取 token。

真正的密码校验、JWT 签发、JWT 验签、用户查询、权限判断都需要你自己实现或接入安全库。

这点面试要讲清楚,否则会显得只会复制教程代码。

五、授权如何设计

授权可以有多种粒度。简单系统可能只需要角色:

def require_admin(user: User = Depends(get_current_user)):
    if "admin" not in user.roles:
        raise HTTPException(status_code=403, detail="权限不足")
    return user

复杂系统还要判断资源归属:

def check_order_owner(order_id: int, user: User):
    order = get_order(order_id)
    if order.user_id != user.id and not user.is_admin:
        raise HTTPException(status_code=403, detail="不能访问该订单")
    return order

也可以设计 RBAC 权限点,例如 user:createorder:readorder:refund。接口依赖声明需要的权限,统一校验用户是否拥有该权限。

六、401 和 403 的区别

401 表示没有通过认证,常见原因是未登录、token 缺失、token 过期、token 无效。响应通常会提示客户端重新登录。

403 表示已经知道你是谁,但你没有权限做这件事。比如普通用户访问管理员接口。

这两个状态码不要混用。混用会影响客户端处理逻辑,也会让接口语义不清楚。

七、安全实践要点

密码不能明文存储,应该使用 bcrypt、argon2 等专门密码哈希算法。JWT 密钥要通过环境变量或密钥管理服务配置,不要写在代码仓库里。

Access token 应该设置合理过期时间。刷新 token 要有单独策略,并考虑设备退出、密码修改后 token 失效等场景。

如果前端运行在浏览器中,还要认真处理 token 存储位置。localStorage 易受 XSS 影响,Cookie 又要处理 CSRF、防跨站策略和 SameSite 配置。没有一种方案无脑完美,要结合业务风险选择。

八、常见误区与追问

场景应返回状态码典型原因
未带 token401客户端未认证
token 过期或签名错误401身份凭证无效
普通用户访问管理接口403已认证但权限不足
访问别人的订单403 或 404取决于是否隐藏资源存在性
登录成功
  -> 签发 access token(例如 15 分钟)
  -> 客户端请求携带 Authorization: Bearer <token>
  -> Depends 解析当前用户
  -> 权限依赖检查角色 / 权限点 / 资源归属

记忆钩子:认证先回答“你是谁”,授权再回答“你能不能做这件事”,JWT 只解决其中一部分。

  • 误区:用了 JWT 就等于实现了权限系统。 JWT 只是携带和验证身份的凭证,角色、权限点、资源归属、撤销策略仍要单独设计。
  • 误区:OAuth2PasswordBearer 会自动完成登录和验签。 它主要负责从 Authorization 头取 Bearer token,并在 OpenAPI 中声明安全方案;密码校验、签发和验签需要自己实现。
  • 误区:认证失败和权限不足都返回 403。 token 缺失、过期、无效属于 401;已认证但不能访问某资源才是 403。
  • 追问:JWT 如何主动失效? 常见做法包括短 access token、refresh token 轮换、服务端黑名单、用户 token_version、密码修改后提升版本号等。
  • 追问:浏览器端 token 放哪里更安全? localStorage 易受 XSS 影响,Cookie 要处理 HttpOnly、Secure、SameSite 和 CSRF;需要结合前端形态和威胁模型选择。
  • 追问:权限校验适合放 Depends 还是业务层? 当前用户解析和通用角色校验适合依赖;订单归属、租户隔离这类资源级规则通常要结合业务查询一起判断。

九、加强记忆

记 FastAPI 认证授权:用 Depends 先认证得到当前用户,再做授权判断;认证失败返回 401,权限不足返回 403。JWT 只是身份凭证方案,不等于完整权限系统,真正的权限还要结合角色、权限点和资源归属。