Files
leaudit-platform-frontend/docs/role-permissions/FRONTEND_API_GUIDE.md
T
TanWenyan 689ef6bc3d fix: 修复角色权限管理模块的API认证和数据加载问题
主要修复:
1. 修复所有RBAC API函数使用axios-client(自动添加JWT token)
   - getRoles, createRole, updateRole, deleteRole 从rbacFetch切换到axios-client
   - 解决401未授权导致的数据加载失败问题

2. 修复用户ID字段不匹配问题
   - getAllUsers函数使用user_id字段(兼容user.user_id || user.id)
   - 确保角色分配时使用正确的用户ID

3. 修复路由ID不匹配问题
   - getRoutes函数改用真实后端API(GET /rbac/user/routes)
   - 解决前端Mock路由ID与数据库不一致导致的400错误

4. 增强axios-client成功响应识别
   - 支持code=200作为成功状态(原本只支持code=0)
   - 兼容不同后端API的响应格式

5. 实现用户单角色限制功能
   - 添加getUserRoles API函数
   - 分配角色前检查用户现有角色
   - 在用户列表中显示当前角色标签

6. 改进创建角色的表单验证
   - role_key必须以字母开头(正则:^[a-z][a-z0-9_]*$)
   - 添加实时验证提示
   - 更新提示文案说明规则

7. 添加删除操作的安全确认机制
   - 删除角色/移除用户角色前显示确认模态框
   - 3秒倒计时后才能确认删除
   - 成功删除后自动刷新数据

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 18:03:57 +08:00

16 KiB
Raw Blame History

用户权限管理接口 - 前端对接文档

📋 文档信息

  • 版本: v2.0
  • 更新日期: 2025-01-24
  • API基础URL: http://YOUR_HOST:8000
  • 认证方式: JWT Bearer Token

⚠️ 重要提示 - 前端对接必读

1. Token过期处理

问题现象: API返回 code: 4001, msg: "token参数无效"

原因: JWT Token已过期(默认有效期1小时)

解决方案:

// 检查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 只能查看和管理自己的数据

调用示例:

// ✅ 正确:使用实际的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. 响应格式说明

所有接口统一返回格式:

{
  "code": 200,
  "msg": "success",
  "data": { ... }
}

部分接口(如用户列表)直接返回数据对象:

{
  "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参数:

{
  page: 1,              // 页码
  page_size: 20,        // 每页数量
  role_key: "",         // 角色标识过滤(可选)
  role_name: "",        // 角色名称模糊搜索(可选)
  include_system: true  // 是否包含系统角色(可选)
}

响应示例:

{
  "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

请求体:

{
  "role_key": "department_leader",
  "role_name": "部门负责人",
  "description": "负责部门日常管理",
  "data_scope": "DEPT",
  "metadata": {}
}

响应示例:

{
  "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参数:

{
  page: 1,
  page_size: 20,
  area: "梅州",      // 按地区过滤(可选)
  username: "admin"  // 用户名模糊搜索(可选)
}

响应示例:

{
  "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

请求体:

{
  "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(仅自己)

响应示例:

{
  "code": 200,
  "message": "权限分配成功",
  "data": {
    "role_id": 2,
    "assigned_count": 2
  }
}

1.5 为用户分配角色

接口: POST /api/v3/rbac/users/{user_id}/roles

请求体:

{
  "role_ids": [1, 2]
}

响应示例:

{
  "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参数:

{
  page: 1,
  page_size: 20,
  ou_id: "000",        // 组织ID过滤(可选)
  is_leader: true,     // 是否领导过滤(可选)
  search: "admin"      // 搜索关键词(可选)
}

响应示例:

{
  "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参数:

{
  include_users: true  // 是否包含用户信息
}

响应示例:

{
  "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

响应示例:

{
  "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

响应示例:

{
  "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

功能说明:

  • 批量更新指定角色的路由权限
  • 采用替换模式:先删除现有所有关联,再插入新关联
  • 自动清除相关缓存(角色缓存 + 用户缓存)

请求体:

{
  "route_ids": [1, 11, 12, 3, 31, 32, 2, 21],
  "permission": "RW"
}

参数说明:

  • route_ids: 路由ID列表(必填)
  • permission: 权限类型,可选值:
    • R: 只读权限
    • W: 只写权限
    • RW: 读写权限(默认)

响应示例:

{
  "code": 200,
  "msg": "success",
  "data": {
    "role_id": 2,
    "assigned_count": 8,
    "removed_count": 5,
    "route_ids": [1, 11, 12, 3, 31, 32, 2, 21]
  }
}

前端调用示例:

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参数:

{
  route_path: "/system/users"
}

响应示例:

{
  "code": 200,
  "msg": "success",
  "data": {
    "route_path": "/system/users",
    "has_access": true
  }
}

🚨 错误码说明

HTTP状态码

状态码 说明 处理建议
200 成功 -
400 请求参数错误 检查请求体格式和必填字段
401 未认证 Token过期或无效,需要重新登录
403 无权限 显示权限不足提示
404 资源不存在 检查ID是否正确
409 冲突 如role_key重复
500 服务器错误 联系后端排查

常见错误处理

// 统一错误处理
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管理权限?

// 方式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_id52, 1, 2
  • 实现Token过期自动刷新机制
  • 处理401/403错误(跳转登录/权限提示)
  • 使用 PUT /rbac/roles/{role_id}/routes 实现路由权限分配
  • 处理 total 字段为0的情况(用数组长度代替)

📞 技术支持

如有问题,请联系后端开发团队。

文档版本: v2.0 最后更新: 2025-01-24 维护者: Backend Team