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. docker学习 容器的启动过程

    这一节我们来稍微了解下docker原理性的东西1    docker run -i -t ubuntu /bin/bash输入上面这行命令,启动一个ubuntu容器时,到底发生了什么?大致过程可以用下 ...

  2. WebKit Inside: 渲染树

    经过CSS的匹配,就要进入渲染树的构建. 渲染树也叫RenderObject树,因为渲染树上每一个节点,都是RenderObject的子类. 首先来看一下RenderObject的继承类图. 1 Re ...

  3. PostgreSQL 密码忘了

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

  4. WSGI、Starlette、Uvicorn 与 Gunicorn 核心介绍及使用指南

    WSGI.Starlette.Uvicorn 与 Gunicorn 的核心介绍及使用指南 一.技术定位与核心差异 WSGI(Web Server Gateway Interface) • 定义:传统的 ...

  5. IDEA强制注册登录版本号:IntelliJ IDEA 2021.2.2

    建议采用 IntelliJ IDEA 2021.2.2 版本进行  Evaluate for free  试用 IntelliJ IDEA 2021.3.3  以前的版本可以不用注册登录idea账户, ...

  6. Asp.net mvc基础(十四)Entity Framework

    一.EntityFramework介绍 1.ORM:Object Relation Mapping,用操作对象的方式来操作数据库 2.ORM工具有很多,其中Dapper.PetaPoco.NHiber ...

  7. js判断iOS还是Android

    /** * 运行设备引擎, 即iOS, Android还是H5 * 返回值注意大小写 * @return iOS, Android, H5 */ function engineType() { let ...

  8. centos7-NFS-网络文件系统

    NFS(network file system)网络文件系统 pdf文档下载链接 https://files.cnblogs.com/files/duxingren/NFS.zip 服务器192.16 ...

  9. rust程序静态编译的两种方法总结

    1. 概述 经过我的探索,总结了两种rust程序静态编译的方法,理论上两种方法都适用于windows.mac os和linux(mac os未验证),实测方法一性能比方法二好,现总结如下,希望能够帮到 ...

  10. MCP 实践系列:EdgeOne 在线部署HTML页面

    今天,我们将专门讲解一下 EdgeOne 在线部署 HTML 页面时所提供的 MCP 功能.这个功能对于个人用户来说非常实用,尤其适合一些小型应用场景,比如开发一个简单的小游戏,或者搭建一个小型网站, ...