""" 权限边界测试套件 测试范围: 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, \ "管理员账户应处于激活状态"