title: 如何在FastAPI中玩转权限控制与测试,让代码安全又优雅?

date: 2025/06/18 10:11:53

updated: 2025/06/18 10:11:53

author: cmdragon

excerpt:

FastAPI通过依赖注入系统实现权限控制,使用Depends()函数接收权限验证依赖项,验证流程包括解析凭证、验证有效性并提取用户角色。权限层级划分为公共端点、用户级端点和管理员端点。单元测试使用pytest验证权限逻辑,集成测试通过httpx模拟请求。完整测试案例包括用户系统权限测试和覆盖率提升技巧。常见问题如401和403错误,解决方案包括检查请求头和用户角色分配。安全加固建议使用HTTPS、设置令牌有效期和记录审计日志。

categories:

  • 后端开发
  • FastAPI

tags:

  • FastAPI
  • 权限控制
  • 依赖注入
  • 单元测试
  • 集成测试
  • JWT
  • 安全加固

扫描二维码

关注或者微信搜一搜:编程智域 前端至全栈交流与成长

发现1000+提升效率与开发的AI工具和实用程序https://tools.cmdragon.cn/

一、FastAPI 权限控制基础实现

1.1 权限控制核心原理

FastAPI 采用依赖注入系统(Dependency Injection)实现权限控制。每个路由通过 Depends() 函数接收权限验证依赖项,验证流程如下:

  1. 客户端发送携带凭证的请求
  2. 依赖项解析 JWT 令牌或 API Key
  3. 验证凭证有效性,提取用户角色
  4. 根据角色判断是否允许访问该端点
from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import OAuth2PasswordBearer app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") # 角色权限校验函数
async def verify_admin(token: str = Depends(oauth2_scheme)):
if token != "admin_token": # 模拟验证逻辑
raise HTTPException(status_code=403, detail="Not authorized")
return {"role": "admin"} # 受保护端点
@app.get("/admin")
async def admin_route(user: dict = Depends(verify_admin)):
return {"message": "Admin access granted"}

1.2 权限层级划分策略

根据业务需求设计权限层级:

  • 公共端点:无需认证(如 /public
  • 用户级端点:需有效令牌(如 /user/profile
  • 管理员端点:需管理员角色(如 /admin/dashboard

二、权限测试核心策略

2.1 单元测试验证权限逻辑

使用 pytest 直接测试权限验证函数:

# 测试文件 test_security.py
from fastapi import HTTPException
import pytest async def test_admin_verification_success():
# 正确令牌测试
result = await verify_admin("admin_token")
assert result["role"] == "admin" async def test_admin_verification_failure():
# 错误令牌测试
with pytest.raises(HTTPException) as exc:
await verify_admin("invalid_token")
assert exc.value.status_code == 403

2.2 集成测试模拟完整请求流

使用 httpx 模拟不同角色用户的请求:

# 测试文件 test_routes.py
from fastapi.testclient import TestClient
from main import app client = TestClient(app) def test_public_access():
response = client.get("/public")
assert response.status_code == 200 def test_admin_access_denied():
# 普通用户访问管理员端点
response = client.get("/admin", headers={"Authorization": "Bearer user_token"})
assert response.status_code == 403
assert "Not authorized" in response.json()["detail"]

三、完整测试案例解析

3.1 用户系统权限测试实现

构建包含多角色的用户管理系统:

# 文件结构
# ├── main.py
# ├── security.py
# └── tests/
# ├── conftest.py
# ├── test_security.py
# └── test_routes.py # security.py 扩展版
from pydantic import BaseModel
from typing import Optional class User(BaseModel):
username: str
role: Optional[str] = "user" async def get_current_user(token: str = Depends(oauth2_scheme)):
# 模拟数据库查询
users = {
"user_token": User(username="john", role="user"),
"admin_token": User(username="admin", role="admin")
}
if token not in users:
raise HTTPException(status_code=401, detail="Invalid token")
return users[token] def check_role(required_role: str):
async def role_checker(user: User = Depends(get_current_user)):
if user.role != required_role:
raise HTTPException(status_code=403, detail="Insufficient permissions") return Depends(role_checker)

3.2 测试覆盖率提升技巧

  • 使用 pytest-cov 生成覆盖率报告
pytest --cov=app --cov-report=html tests/
  • 覆盖所有权限分支场景:

    • 合法令牌+正确角色
    • 合法令牌+错误角色
    • 无效令牌
    • 缺失认证头

四、常见问题解决方案

4.1 典型报错处理

问题 1:401 Unauthorized

{
"detail": "Not authenticated"
}

原因

  • 请求未携带 Authorization 头
  • 令牌格式错误(如缺少 Bearer 前缀)

解决

# 正确请求头示例
headers = {
"Authorization": "Bearer admin_token"
}

问题 2:403 Forbidden

{
"detail": "Insufficient permissions"
}

分析步骤

  1. 检查用户角色分配是否正确
  2. 验证权限依赖项是否正确定义
  3. 测试直接调用权限验证函数

4.2 安全加固最佳实践

  1. 使用 HTTPS 加密所有通信
  2. 令牌设置合理有效期(JWT 的 exp 声明)
  3. 敏感操作记录审计日志

课后 Quiz

  1. 如何测试用户权限升级场景?

    A) 修改数据库角色字段

    B) 使用权限验证函数的 mock 对象

    C) 直接修改 JWT 令牌内容

  2. 收到 422 Unprocessable Entity 错误应首先检查?

    A) 服务器防火墙设置

    B) 请求体数据格式

    C) 数据库连接状态

答案解析

  1. 正确答案 B。通过 mock 返回不同角色用户对象,避免直接操作数据库或令牌
  2. 正确答案 B。422 错误通常表示请求体不符合 Pydantic 模型验证规则

运行环境配置

pip install fastapi==0.68.0 uvicorn==0.15.0 pydantic==1.10.7
pip install pytest==6.2.5 httpx==0.19.0 pytest-cov==3.0.0

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:如何在FastAPI中玩转权限控制与测试,让代码安全又优雅? | cmdragon's Blog

往期文章归档:

如何在FastAPI中玩转权限控制与测试,让代码安全又优雅?的更多相关文章

  1. (转)浅析Java中的访问权限控制

    原文地址: http://www.cnblogs.com/dolphin0520/p/3734915.html 今天我们来一起了解一下Java语言中的访问权限控制.在讨论访问权限控制之前,先来讨论一下 ...

  2. 浅析Java中的访问权限控制

    浅析Java中的访问权限控制 今天我们来一起了解一下Java语言中的访问权限控制.在讨论访问权限控制之前,先来讨论一下为何需要访问权限控制.考虑两个场景: 场景1:工程师A编写了一个类ClassA,但 ...

  3. IOS中实例的权限控制

    @public.@protected.@private的使用 在OC中声明一个类的时候,可以使用上面 @public.@protected.@private三个关键字声明实例的权限,例如下面的代码: ...

  4. .NetCore中如何实现权限控制 基于Claim角色、策略、基于Claim功能点处理

    .NetCore中如果实现权限控制的问题,当我们访问到一个Action操作的时候,我们需要进行权限控制 基于claims 角色控制 基于角色控制总觉得范围有点过大,而且控制起来感觉也不是太好,举一个例 ...

  5. 【TypeScript】如何在TypeScript中使用async/await,让你的代码更像C#。

    [TypeScript]如何在TypeScript中使用async/await,让你的代码更像C#. async/await 提到这个东西,大家应该都很熟悉.最出名的可能就是C#中的,但也有其它语言也 ...

  6. Java中的访问权限控制

    Java提供了public, private, protected 三个访问权限修饰词,提供了以下四种访问权限控制机制: 1.包访问权限: 2.Public访问权限: 3.Private访问权限: 4 ...

  7. WPF wpf中按钮操作权限控制

    权限控制我们有很多种方式可以实现. 这次项目中做个简单的权限控制,我们在所有按钮触发前判断,有权限则可执行. 我们自定义一个命令类. public class DelegateCommand : IC ...

  8. pc vue 项目中的菜单权限控制

    在pc 管理系统这种类型的产品,通常会涉及到账号权限的控制,不同的账号权限能浏览的功能模块是不同的,对应侧边栏菜单模块的显示也会不同. 场景一.(电商类管理系统) 登录 登录后,依次获取账号 toke ...

  9. ThinkPHP中:RBAC权限控制的实习步骤

    使用版本ThinkPHP3.1.3 第一步,建表及数据 第二步,建关联模型 第三步,控制器使用关联模型.配置文件 第四步,模板显示数据 第一步,建表及数据 在数据库中,建立一个companysvn数据 ...

  10. 在PyCharm中以root权限运行和调试python代码

    python中有的代码可能需要su权限,如 import os os.mkdir('/media/xxx/disk_a') 如果在交互式环境中使用,需要以sudo的方式启动python.而在PyCha ...

随机推荐

  1. 关于普通程序员该如何参与AI学习的三个建议以及自己的实践

    大部分程序员在学习大语言模型的时候都比较痛苦,感觉AI是如此之近又如此之远,仿佛能搞明白一点,又好像什么也没明白.就像我们在很远的地方看珠穆拉玛峰,感觉它就像一个不大的山包,感觉只要自己做足准备咬咬牙 ...

  2. 堆排序(标准版)(NB)

    博客地址:https://www.cnblogs.com/zylyehuo/ # _*_coding:utf-8_*_ import random def sift(li, low, high): # ...

  3. 系统自带模版在 emlog pro 1.8.0 底部信息错位问题暂时的解决方案

    问题描述 作为一名 emlog 爱好者,笔者闲暇时间经常为 emlog 系统的 Github 仓库里( https://github.com/emlog/emlog )提 pr 和修修补补,就像其他知 ...

  4. PostgreSQL 密码忘了

    许久不登, 倒是把默认的 postgres 用户的密码给忘了... 首先关闭 PostgreSQL. 我这是 Windows 上安装的, 所以到服务 (services.msc) 里关闭. 然后修改配 ...

  5. JSON Objects Framework(1)

    学习datasnap,json必须掌握.用自身的JSON,就必须熟悉JSON Objects Framework.其中tostring和value区别就是一个坑. The JSON objects f ...

  6. 卸载重装vscode

    最近工作需要长期用到python,但我的老电脑又实在拉不起pycharm那配置,干脆就用vscode了,但本来我的vscode是用来写c/c++的,安装配置一通乱搞,现在也不知道怎么配置回来了. 干脆 ...

  7. JSON对象、JSON字符串和Java对象互相转

    JSON对象.JSON字符串和Java对象互相转 Java对象转json字符串(一般使用字符串存储redis或者数据库) public static String toJSONString(Objec ...

  8. 在web.xml下配置springmvc的核心控制器

    <!DOCTYPE web-app PUBLIC        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" ...

  9. 多线程的waiting与notify

    一.waiting()与notify() /* 进入到TimeWaiting(计时等待)有两种方式 1.使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Block ...

  10. python批量检测链接是否可正常打开

    通过一些爬虫脚本爬取图站图片,但是发现有些图片是没法打开的,可能返回404的code码 所以设计一个脚本,对所有的图片地址进行检查,返回200的保存到另外一个文本内,然后再去下载 脚本逻辑很简单,直接 ...