# 用户权限管理接口 - 前端对接文档 ## 📋 文档信息 - **版本**: v2.0 - **更新日期**: 2025-01-24 - **API基础URL**: `http://YOUR_HOST:8000` - **认证方式**: JWT Bearer Token --- ## ⚠️ 重要提示 - 前端对接必读 ### 1. Token过期处理 **问题现象**: API返回 `code: 4001, msg: "token参数无效"` **原因**: JWT Token已过期(默认有效期1小时) **解决方案**: ```javascript // 检查Token是否过期 const isTokenExpired = (token) => { try { const payload = JSON.parse(atob(token.split('.')[1])); return Date.now() >= payload.exp * 1000; } catch { return true; } }; // 在发送请求前检查 if (isTokenExpired(token)) { await login(); // 重新登录获取新Token } ``` ### 2. 实际角色ID对应关系 ⚠️ **数据库中的实际角色ID** (请以实际数据为准): | 角色名称 | role_key | 实际role_id | 说明 | |---------|----------|------------|------| | 省级管理员 | provincial_admin | **52** | 拥有完整RBAC管理权限 | | 市级管理员 | admin | **1** | 负责本地区业务管理 | | 普通员工 | common | **2** | 只能查看和管理自己的数据 | **调用示例**: ```javascript // ✅ 正确:使用实际的role_id const provincialAdminUsers = await getRoleUsers(52); const adminUsers = await getRoleUsers(1); const commonUsers = await getRoleUsers(2); // ❌ 错误:使用Mock数据的ID const wrongUsers = await getRoleUsers(3); // 数据库中不存在 ``` ### 3. 响应格式说明 所有接口统一返回格式: ```json { "code": 200, "msg": "success", "data": { ... } } ``` 部分接口(如用户列表)直接返回数据对象: ```json { "users": [...], "total": 10 } ``` ### 4. 权限要求 | 接口模块 | 权限要求 | 说明 | |---------|----------|------| | RBAC管理接口 | `system:rbac:manage` | 仅provincial_admin角色 | | 用户管理接口 | JWT认证即可 | 所有登录用户 | | 路由权限接口 | JWT认证即可 | 所有登录用户 | --- ## 📚 接口总览 ### 一、RBAC管理接口(18个) **基础路径**: `/api/v3/rbac` #### 1.1 角色管理(5个接口) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/roles` | 获取角色列表(支持分页、搜索) | | GET | `/roles/{role_id}` | 获取角色详情 | | POST | `/roles` | 创建角色 | | PUT | `/roles/{role_id}` | 更新角色 | | DELETE | `/roles/{role_id}` | 删除角色(支持force参数) | #### 1.2 权限管理(5个接口) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/permissions` | 获取权限列表(支持树形/平铺) | | GET | `/permissions/{permission_id}` | 获取权限详情 | | POST | `/permissions` | 创建权限 | | PUT | `/permissions/{permission_id}` | 更新权限 | | DELETE | `/permissions/{permission_id}` | 删除权限 | #### 1.3 角色权限关联(4个接口) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/roles/{role_id}/permissions` | 获取角色的所有权限 | | POST | `/roles/{role_id}/permissions` | 批量分配权限给角色(支持替换/追加) | | PUT | `/roles/{role_id}/permissions/{permission_id}` | 更新单个权限配置 | | DELETE | `/roles/{role_id}/permissions/{permission_id}` | 移除角色权限 | #### 1.4 用户角色管理(4个接口) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/roles/{role_id}/users` | 获取拥有某角色的用户列表 | | GET | `/users/{user_id}/roles` | 获取用户的所有角色 | | POST | `/users/{user_id}/roles` | 为用户分配角色 | | DELETE | `/users/{user_id}/roles/{role_id}` | 移除用户角色 | ### 二、用户管理接口(3个) **基础路径**: `/admin/users` | 方法 | 路径 | 说明 | |------|------|------| | GET | `/users` | 获取用户列表(支持分页、搜索) | | GET | `/organizations` | 获取组织架构(树形结构) | | GET | `/organizations/flat` | 获取组织列表(扁平结构) | ### 三、路由权限接口(5个) **基础路径**: `/rbac` | 方法 | 路径 | 说明 | |------|------|------| | GET | `/user/routes` | 获取当前用户可访问路由(树形) | | GET | `/user/routes/flat` | 获取当前用户可访问路由(扁平) | | GET | `/roles/{role_id}/routes` | 获取角色可访问路由 | | PUT | `/roles/{role_id}/routes` | **批量更新角色路由权限** ⭐新增 | | GET | `/check-route` | 检查路由访问权限 | --- ## 📖 详细接口说明 ## 一、RBAC管理接口 ### 1.1 获取角色列表 **接口**: `GET /api/v3/rbac/roles` **Query参数**: ```javascript { page: 1, // 页码 page_size: 20, // 每页数量 role_key: "", // 角色标识过滤(可选) role_name: "", // 角色名称模糊搜索(可选) include_system: true // 是否包含系统角色(可选) } ``` **响应示例**: ```json { "code": 200, "message": "success", "data": { "total": 3, "page": 1, "page_size": 20, "items": [ { "id": 52, "role_key": "provincial_admin", "role_name": "省级管理员", "description": "省级权限,可管理所有地区", "data_scope": "ALL", "is_system": true, "user_count": 1, "permission_count": 15 }, { "id": 1, "role_key": "admin", "role_name": "市级管理员", "data_scope": "DEPT", "is_system": true, "user_count": 6 } ] } } ``` --- ### 1.2 创建角色 **接口**: `POST /api/v3/rbac/roles` **请求体**: ```json { "role_key": "department_leader", "role_name": "部门负责人", "description": "负责部门日常管理", "data_scope": "DEPT", "metadata": {} } ``` **响应示例**: ```json { "code": 200, "message": "角色创建成功", "data": { "id": 6, "role_key": "department_leader", "role_name": "部门负责人", "data_scope": "DEPT", "is_system": false } } ``` --- ### 1.3 获取角色的所有用户 **接口**: `GET /api/v3/rbac/roles/{role_id}/users` **Query参数**: ```javascript { page: 1, page_size: 20, area: "梅州", // 按地区过滤(可选) username: "admin" // 用户名模糊搜索(可选) } ``` **响应示例**: ```json { "code": 200, "message": "success", "data": { "total": 6, "page": 1, "page_size": 20, "items": [ { "user_id": 8, "username": "梅州烟草", "nick_name": "梅州烟草", "area": "梅州管理员账号", "ou_name": "梅州管理员账号", "phone_number": null, "email": null, "assigned_at": "2025-11-18T01:40:25.030949+00:00" } ] } } ``` --- ### 1.4 批量分配权限给角色 **接口**: `POST /api/v3/rbac/roles/{role_id}/permissions` **请求体**: ```json { "permissions": [ { "permission_id": 10, "grant_type": "GRANT", "data_scope": "ALL" }, { "permission_id": 11, "grant_type": "GRANT", "data_scope": "DEPT" } ], "replace": true } ``` **参数说明**: - `replace`: true=替换全部权限,false=追加权限 - `grant_type`: GRANT(授予)或 DENY(拒绝) - `data_scope`: ALL(全部数据)/ DEPT(本部门)/ SELF(仅自己) **响应示例**: ```json { "code": 200, "message": "权限分配成功", "data": { "role_id": 2, "assigned_count": 2 } } ``` --- ### 1.5 为用户分配角色 **接口**: `POST /api/v3/rbac/users/{user_id}/roles` **请求体**: ```json { "role_ids": [1, 2] } ``` **响应示例**: ```json { "code": 200, "message": "角色分配成功", "data": { "user_id": 20, "username": "test_user", "assigned_roles": [ {"role_id": 1, "role_name": "市级管理员"}, {"role_id": 2, "role_name": "普通员工"} ] } } ``` **注意事项**: - ⚠️ 不能给自己分配角色(防止提权) - ⚠️ provincial_admin角色只能由省级管理员分配 - ⚠️ admin角色只能给本地区用户分配角色 --- ## 二、用户管理接口 ### 2.1 获取用户列表 **接口**: `GET /admin/users/users` **Query参数**: ```javascript { page: 1, page_size: 20, ou_id: "000", // 组织ID过滤(可选) is_leader: true, // 是否领导过滤(可选) search: "admin" // 搜索关键词(可选) } ``` **响应示例**: ```json { "users": [ { "id": 5, "username": "admin", "nick_name": "admin", "ou_id": "000", "ou_name": "test", "is_leader": true, "status": 0 } ], "total": 10 } ``` ⚠️ **已知问题**: 当前版本 `total` 字段返回0,请以 `users` 数组长度为准。 --- ### 2.2 获取组织架构(树形) **接口**: `GET /admin/users/organizations` **Query参数**: ```javascript { include_users: true // 是否包含用户信息 } ``` **响应示例**: ```json { "organizations": [ { "ou_id": "000", "ou_name": "总部", "parent_ou_id": null, "level": 0, "children": [ { "ou_id": "0000000A1ML", "ou_name": "梅州市局", "parent_ou_id": "000", "level": 1, "users": [ { "id": 8, "username": "梅州烟草", "nick_name": "梅州烟草", "ou_id": "0000000A1ML", "ou_name": "梅州市局" } ] } ], "users": [] } ], "total_organizations": 5, "total_users": 10 } ``` --- ## 三、路由权限接口 ### 3.1 获取当前用户可访问路由 **接口**: `GET /rbac/user/routes` **响应示例**: ```json { "code": 200, "msg": "success", "data": { "user_id": 5, "username": "admin", "routes": [ { "id": 1, "route_path": "/", "route_name": "Home", "route_title": "首页", "component": "Layout", "parent_id": null, "icon": "home", "sort_order": 0, "is_hidden": false, "is_cache": true, "meta": {}, "children": [ { "id": 11, "route_path": "/dashboard", "route_name": "Dashboard", "route_title": "工作台", "parent_id": 1 } ] } ], "routes_flat": [ {"id": 1, "route_path": "/", "route_name": "Home"}, {"id": 11, "route_path": "/dashboard", "route_name": "Dashboard"} ] } } ``` **说明**: - `routes`: 树形结构(用于构建菜单) - `routes_flat`: 扁平结构(用于路由守卫权限检查) --- ### 3.2 获取角色可访问路由 **接口**: `GET /rbac/roles/{role_id}/routes` **响应示例**: ```json { "code": 200, "msg": "success", "data": { "role_id": 2, "routes": [ {"id": 1, "route_path": "/", "route_name": "Home", "route_title": "首页"}, {"id": 11, "route_path": "/dashboard", "route_name": "Dashboard"} ] } } ``` --- ### 3.3 批量更新角色路由权限 ⭐新增 **接口**: `PUT /rbac/roles/{role_id}/routes` **功能说明**: - 批量更新指定角色的路由权限 - 采用**替换模式**:先删除现有所有关联,再插入新关联 - 自动清除相关缓存(角色缓存 + 用户缓存) **请求体**: ```json { "route_ids": [1, 11, 12, 3, 31, 32, 2, 21], "permission": "RW" } ``` **参数说明**: - `route_ids`: 路由ID列表(必填) - `permission`: 权限类型,可选值: - `R`: 只读权限 - `W`: 只写权限 - `RW`: 读写权限(默认) **响应示例**: ```json { "code": 200, "msg": "success", "data": { "role_id": 2, "assigned_count": 8, "removed_count": 5, "route_ids": [1, 11, 12, 3, 31, 32, 2, 21] } } ``` **前端调用示例**: ```javascript const updateRoleRoutes = async (roleId, routeIds) => { const response = await fetch(`/rbac/roles/${roleId}/routes`, { method: 'PUT', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ route_ids: routeIds, permission: 'RW' }) }); const result = await response.json(); if (result.code === 200) { console.log(`成功分配 ${result.data.assigned_count} 个路由`); console.log(`移除了 ${result.data.removed_count} 个旧路由`); } return result; }; // 使用示例 await updateRoleRoutes(2, [1, 11, 12, 3, 31, 32, 2, 21]); ``` **注意事项**: - ⚠️ 所有 `route_ids` 必须存在且未删除 - ⚠️ 使用事务确保数据一致性 - ⚠️ 会自动清除所有受影响用户的路由缓存 --- ### 3.4 检查路由访问权限 **接口**: `GET /rbac/check-route` **Query参数**: ```javascript { route_path: "/system/users" } ``` **响应示例**: ```json { "code": 200, "msg": "success", "data": { "route_path": "/system/users", "has_access": true } } ``` --- ## 🚨 错误码说明 ### HTTP状态码 | 状态码 | 说明 | 处理建议 | |--------|------|---------| | 200 | 成功 | - | | 400 | 请求参数错误 | 检查请求体格式和必填字段 | | 401 | 未认证 | Token过期或无效,需要重新登录 | | 403 | 无权限 | 显示权限不足提示 | | 404 | 资源不存在 | 检查ID是否正确 | | 409 | 冲突 | 如role_key重复 | | 500 | 服务器错误 | 联系后端排查 | ### 常见错误处理 ```javascript // 统一错误处理 const handleError = (error) => { if (error.response?.status === 401) { // Token过期,跳转登录 localStorage.removeItem('token'); window.location.href = '/login'; } else if (error.response?.status === 403) { alert('权限不足'); } else if (error.response?.data?.detail) { alert(error.response.data.detail); } else { alert('操作失败,请稍后重试'); } }; ``` --- ## 💡 常见问题FAQ ### Q1: 为什么所有接口返回 code: 4001? **A**: Token已过期,请重新登录获取新Token ### Q2: role_id应该用哪个?文档里写的1,2,3还是52,1,2? **A**: 使用实际数据库中的ID: - provincial_admin = **52** - admin = **1** - common = **2** ### Q3: 需要用Mock数据吗? **A**: **不需要**,所有接口已完整实现,直接调用真实API ### Q4: 如何判断当前用户是否有RBAC管理权限? ```javascript // 方式1:检查JWT中的user_role const payload = JSON.parse(atob(token.split('.')[1])); const isProvincialAdmin = payload.user_role === 'provincial_admin'; // 方式2:调用权限检查接口(推荐) const routes = await fetch('/rbac/user/routes'); const hasRBACAccess = routes.data.routes.some(r => r.route_path === '/rbac'); ``` ### Q5: 如何实现角色权限页面的路由分配功能? **A**: 使用新的批量更新接口 `PUT /rbac/roles/{role_id}/routes`: 1. 通过 `GET /rbac/roles/{role_id}/routes` 获取当前角色已有路由 2. 用户选择要分配的路由ID列表 3. 调用 `PUT /rbac/roles/{role_id}/routes` 提交更新 4. 接口会自动替换所有路由权限并清除缓存 ### Q6: total字段为什么返回0? **A**: `/admin/users/users` 接口的 `total` 字段当前版本存在bug,请以 `users` 数组长度为准。该问题已记录,将在后续版本修复。 ### Q7: 批量更新路由权限后,用户需要重新登录吗? **A**: 不需要。接口会自动清除相关用户的路由缓存,用户刷新页面即可看到新权限。 --- ## 📦 前端开发清单 - [ ] 移除所有RBAC相关的Mock数据 - [ ] 使用实际的role_id(52, 1, 2) - [ ] 实现Token过期自动刷新机制 - [ ] 处理401/403错误(跳转登录/权限提示) - [ ] 使用 `PUT /rbac/roles/{role_id}/routes` 实现路由权限分配 - [ ] 处理 `total` 字段为0的情况(用数组长度代替) --- ## 📞 技术支持 如有问题,请联系后端开发团队。 **文档版本**: v2.0 **最后更新**: 2025-01-24 **维护者**: Backend Team