1e3dc11d59
feat(test-suite): 新增测试套件模块,包含API测试客户端和测试配置 fix(api): 修复数据库实体和仓库的删除操作返回值 style(api): 统一数据库表名和字段命名 perf(api): 添加缓存注解提升配置查询性能 test(api): 添加H2测试数据库配置支持 chore: 清理旧的测试文件和脚本
276 lines
8.7 KiB
Python
276 lines
8.7 KiB
Python
"""
|
|
权限边界测试套件
|
|
|
|
测试范围:
|
|
1. 角色权限边界测试
|
|
2. 数据访问权限测试
|
|
3. 操作权限测试
|
|
4. 菜单权限测试
|
|
5. API权限测试
|
|
|
|
作者: 张翔
|
|
日期: 2026-04-01
|
|
"""
|
|
|
|
import pytest
|
|
from api.auth_api import AuthAPI
|
|
from api.user_api import UserAPI
|
|
from api.role_api import RoleAPI
|
|
from api.menu_api import MenuAPI
|
|
from config.settings import settings
|
|
|
|
|
|
@pytest.mark.security
|
|
@pytest.mark.asyncio
|
|
class TestPermissionBoundary:
|
|
"""权限边界测试类"""
|
|
|
|
async def test_role_based_access_control(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-01: 基于角色的访问控制
|
|
|
|
验证点:
|
|
1. 不同角色有不同权限
|
|
2. 权限正确分配
|
|
3. 权限正确验证
|
|
"""
|
|
role_api = RoleAPI(authenticated_client)
|
|
|
|
roles_response = await role_api.get_roles_by_page()
|
|
assert roles_response.status_code == 200
|
|
|
|
roles = roles_response.json().get("content", [])
|
|
assert len(roles) > 0, "应至少有一个角色"
|
|
|
|
for role in roles:
|
|
assert "roleName" in role, "角色应包含名称"
|
|
assert "roleKey" in role, "角色应包含标识"
|
|
|
|
async def test_user_data_isolation(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-02: 用户数据隔离
|
|
|
|
验证点:
|
|
1. 用户只能访问自己的数据
|
|
2. 无法访问其他用户敏感信息
|
|
3. 管理员可访问所有数据
|
|
"""
|
|
user_api = UserAPI(authenticated_client)
|
|
|
|
users_response = await user_api.get_users_by_page()
|
|
assert users_response.status_code == 200
|
|
|
|
users = users_response.json().get("content", [])
|
|
|
|
for user in users:
|
|
if "password" in user:
|
|
assert user["password"] != "admin123", \
|
|
"密码不应明文返回"
|
|
assert not user["password"].startswith("$2"), \
|
|
"密码哈希不应返回给前端"
|
|
|
|
async def test_cross_user_access_prevention(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-03: 跨用户访问防护
|
|
|
|
验证点:
|
|
1. 普通用户无法修改其他用户数据
|
|
2. 用户ID绑定验证
|
|
"""
|
|
user_api = UserAPI(authenticated_client)
|
|
|
|
users_response = await user_api.get_users_by_page()
|
|
users = users_response.json().get("content", [])
|
|
|
|
if len(users) > 1:
|
|
other_user = next(
|
|
(u for u in users if u.get("username") != "admin"),
|
|
None
|
|
)
|
|
|
|
if other_user:
|
|
response = await user_api.get_user_by_id(other_user["id"])
|
|
|
|
assert response.status_code in [200, 403], \
|
|
"应正确处理跨用户访问"
|
|
|
|
async def test_menu_permission_control(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-04: 菜单权限控制
|
|
|
|
验证点:
|
|
1. 不同角色看到不同菜单
|
|
2. 菜单权限标识验证
|
|
3. 无权限菜单隐藏
|
|
"""
|
|
menu_api = MenuAPI(authenticated_client)
|
|
|
|
menus_response = await menu_api.get_menus()
|
|
assert menus_response.status_code == 200
|
|
|
|
menus = menus_response.json() if isinstance(
|
|
menus_response.json(), list
|
|
) else menus_response.json().get("data", [])
|
|
|
|
for menu in menus:
|
|
assert "menuName" in menu or "name" in menu, \
|
|
"菜单应包含名称"
|
|
|
|
async def test_api_permission_validation(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-05: API权限验证
|
|
|
|
验证点:
|
|
1. 每个API有权限控制
|
|
2. 无权限返回403
|
|
3. 未认证返回401
|
|
"""
|
|
user_api = UserAPI(authenticated_client)
|
|
|
|
client_without_auth = authenticated_client.__class__(
|
|
base_url=settings.API_BASE_URL
|
|
)
|
|
|
|
user_api_no_auth = UserAPI(client_without_auth)
|
|
response = await user_api_no_auth.get_users_by_page()
|
|
|
|
assert response.status_code in [401, 403], \
|
|
"未认证请求应被拒绝"
|
|
|
|
async def test_privilege_escalation_prevention(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-06: 权限提升防护
|
|
|
|
验证点:
|
|
1. 用户无法自我提升权限
|
|
2. 角色修改需管理员权限
|
|
"""
|
|
user_api = UserAPI(authenticated_client)
|
|
role_api = RoleAPI(authenticated_client)
|
|
|
|
users_response = await user_api.get_users_by_page()
|
|
users = users_response.json().get("content", [])
|
|
|
|
current_user = next(
|
|
(u for u in users if u.get("username") == "admin"),
|
|
None
|
|
)
|
|
|
|
if current_user:
|
|
roles_response = await role_api.get_roles_by_page()
|
|
roles = roles_response.json().get("content", [])
|
|
|
|
admin_role = next(
|
|
(r for r in roles if "admin" in r.get("roleKey", "").lower()),
|
|
None
|
|
)
|
|
|
|
assert admin_role is not None, "应存在管理员角色"
|
|
|
|
async def test_operation_permission_check(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-07: 操作权限检查
|
|
|
|
验证点:
|
|
1. 创建操作需权限
|
|
2. 修改操作需权限
|
|
3. 删除操作需权限
|
|
"""
|
|
user_api = UserAPI(authenticated_client)
|
|
|
|
test_user_data = {
|
|
"username": "perm_test_user",
|
|
"password": "Test123!@#",
|
|
"email": "perm_test@test.com",
|
|
"phone": "13800138000",
|
|
"status": 1
|
|
}
|
|
|
|
create_response = await user_api.create_user(test_user_data)
|
|
|
|
if create_response.status_code in [201, 200]:
|
|
user_id = create_response.json().get("id")
|
|
|
|
update_response = await user_api.update_user(
|
|
user_id,
|
|
{"email": "updated@test.com"}
|
|
)
|
|
|
|
assert update_response.status_code in [200, 403]
|
|
|
|
delete_response = await user_api.delete_user(user_id)
|
|
|
|
assert delete_response.status_code in [200, 204, 403]
|
|
|
|
async def test_data_filter_by_permission(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-08: 数据权限过滤
|
|
|
|
验证点:
|
|
1. 查询结果按权限过滤
|
|
2. 敏感字段脱敏
|
|
"""
|
|
user_api = UserAPI(authenticated_client)
|
|
|
|
users_response = await user_api.get_users_by_page()
|
|
|
|
if users_response.status_code == 200:
|
|
users = users_response.json().get("content", [])
|
|
|
|
for user in users:
|
|
assert "password" not in user or \
|
|
user.get("password") == "******", \
|
|
"密码字段应脱敏或不返回"
|
|
|
|
async def test_role_permission_inheritance(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-09: 角色权限继承
|
|
|
|
验证点:
|
|
1. 角色权限可继承
|
|
2. 子角色权限不超过父角色
|
|
"""
|
|
role_api = RoleAPI(authenticated_client)
|
|
|
|
roles_response = await role_api.get_roles_by_page()
|
|
|
|
if roles_response.status_code == 200:
|
|
roles = roles_response.json().get("content", [])
|
|
|
|
for role in roles:
|
|
if "parentId" in role and role["parentId"]:
|
|
parent_role = next(
|
|
(r for r in roles if r.get("id") == role["parentId"]),
|
|
None
|
|
)
|
|
|
|
async def test_admin_privilege_boundary(self, authenticated_client):
|
|
"""
|
|
SEC-PERM-10: 管理员权限边界
|
|
|
|
验证点:
|
|
1. 超级管理员有所有权限
|
|
2. 普通管理员权限受限
|
|
3. 管理员操作审计
|
|
"""
|
|
user_api = UserAPI(authenticated_client)
|
|
role_api = RoleAPI(authenticated_client)
|
|
|
|
users_response = await user_api.get_users_by_page()
|
|
assert users_response.status_code == 200
|
|
|
|
roles_response = await role_api.get_roles_by_page()
|
|
assert roles_response.status_code == 200
|
|
|
|
users = users_response.json().get("content", [])
|
|
roles = roles_response.json().get("content", [])
|
|
|
|
admin_user = next(
|
|
(u for u in users if u.get("username") == "admin"),
|
|
None
|
|
)
|
|
|
|
if admin_user:
|
|
assert admin_user.get("status") == 1, \
|
|
"管理员账户应处于激活状态"
|