# RBAC 权限管理完整指南 v3.3 ## 📋 文档说明 本文档是 v3.3 版本的 RBAC(基于角色的访问控制)和用户管理的**完整指南**,包含: - ✅ 核心业务逻辑的详细说明 - ✅ 所有接口的完整定义和请求参数 - ✅ 实际数据库数据示例 - ✅ 权限控制和地区隔离规则 - ✅ 完整的前后端对接示例 **适用对象**:后端开发、前端开发、产品经理、测试人员 --- ## 目录 - [1. 核心业务逻辑](#1-核心业务逻辑) - [1.1 设计理念](#11-设计理念) - [1.2 数据模型](#12-数据模型) - [1.3 权限控制规则](#13-权限控制规则) - [2. 完整接口文档](#2-完整接口文档) - [2.1 角色管理接口](#21-角色管理接口) - [2.2 用户管理接口](#22-用户管理接口) - [2.3 角色分配接口](#23-角色分配接口) - [3. 业务场景示例](#3-业务场景示例) - [4. 数据库实际数据](#4-数据库实际数据) - [5. 前端对接指南](#5-前端对接指南) --- ## 1. 核心业务逻辑 ### 1.1 设计理念 #### 三层设计架构 ``` ┌─────────────────────────────────────────────────────────┐ │ 1. 角色层(全局统一) │ ├─────────────────────────────────────────────────────────┤ │ - 角色是全局配置,不区分地区 │ │ - 所有用户都能看到所有角色 │ │ - 角色包括:provincial_admin, admin, common │ └─────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 2. 用户层(地区隔离) │ ├─────────────────────────────────────────────────────────┤ │ - 用户按地区(area字段)隔离管理 │ │ - 省级管理员可以操作所有地区用户 │ │ - 市级管理员只能操作同地区用户 │ └─────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 3. 权限层(操作控制) │ ├─────────────────────────────────────────────────────────┤ │ - 查看权限:所有登录用户 │ │ - 分配权限:省级/市级管理员(受地区限制) │ │ - 修改配置:仅省级管理员 │ └─────────────────────────────────────────────────────────┘ ``` #### 核心原则 | 原则 | 说明 | 示例 | |-----|------|------| | **角色统一** | 角色是全局的,不分地区 | 梅州和云浮都使用相同的 admin 角色 | | **用户隔离** | 用户按地区管理,市级管理员只能操作同地区用户 | 梅州管理员只能管理梅州的用户 | | **权限分层** | 查看开放,修改受限 | 所有人能看角色列表,只有省级能改角色权限 | --- ### 1.2 数据模型 #### 数据库表结构 **1. roles 表(角色表)** | 字段 | 类型 | 说明 | 示例 | |------|------|------|------| | `id` | integer | 角色ID(主键) | 1, 2, 52 | | `role_key` | varchar(30) | 角色标识(唯一) | admin, common, provincial_admin | | `role_name` | varchar(50) | 角色名称 | 市级管理员, 普通员工, 省级管理员 | | `description` | varchar(200) | 角色描述 | 负责本地区的所有业务管理 | | `is_system_role` | boolean | 是否系统角色 | true, false | | `created_at` | timestamp | 创建时间 | 2025-01-15 10:30:00 | **实际数据**: ```json [ { "id": 1, "role_key": "admin", "role_name": "市级管理员", "description": "负责本地区的所有业务管理,不包括系统设置和角色权限管理" }, { "id": 2, "role_key": "common", "role_name": "普通员工", "description": "仅能操作自己的数据" }, { "id": 52, "role_key": "provincial_admin", "role_name": "省级管理员", "description": "拥有全部权限,可以管理所有地区的评查点规则" } ] ``` --- **2. sso_users 表(用户表)** | 字段 | 类型 | 说明 | 示例 | |------|------|------|------| | `id` | integer | 用户ID(主键) | 5, 6, 8 | | `username` | varchar(255) | 用户名 | admin, 梅州烟草 | | `nick_name` | varchar(255) | 昵称 | 张三, 李四 | | `area` | varchar(255) | **地区**(用于权限隔离)⭐ | 梅州, 云浮, 揭阳, 潮州 | | `ou_name` | varchar(255) | **部门名称**(用于组织划分) | 测试技术部, 研发部 | | `ou_id` | varchar(255) | 组织单位ID | 0000000A1ML | | `status` | smallint | 用户状态(0=正常) | 0 | **实际数据(按地区分组)**: ```json { "梅州": [ {"id": 5, "username": "admin", "nick_name": "admin", "area": "梅州", "ou_name": "test"}, {"id": 6, "username": "烟草科技", "nick_name": "烟草科技", "area": "梅州", "ou_name": "测试技术部"}, {"id": 8, "username": "梅州烟草", "nick_name": "梅州烟草", "area": "梅州", "ou_name": "梅州管理员账号"}, {"id": 19, "username": "test_admin", "nick_name": "测试管理员", "area": "梅州"}, {"id": 20, "username": "test_normal", "nick_name": "测试普通用户", "area": "梅州"}, {"id": 21, "username": "test_other", "nick_name": "测试其他用户", "area": "梅州"} ], "云浮": [ {"id": 9, "username": "云浮烟草", "nick_name": "云浮烟草", "area": "云浮"}, {"id": 22, "username": "OAuth已存在用户测试", "area": "云浮"} ], "揭阳": [ {"id": 7, "username": "揭阳惠来烟草", "area": "揭阳"} ], "潮州": [ {"id": 12, "username": "潮州烟草", "area": "潮州"} ] } ``` **⚠️ 重要区分**: - `area`:**地区**(省/市级别),用于**权限隔离** - `ou_name`:**部门名称**(部门级别),用于**组织划分** --- **3. user_role 表(用户角色关联表)** | 字段 | 类型 | 说明 | |------|------|------| | `id` | integer | 主键 | | `user_id` | integer | 用户ID(外键 → sso_users.id) | | `role_id` | integer | 角色ID(外键 → roles.id) | | `created_at` | timestamp | 分配时间 | **实际数据**: ```json [ {"user_id": 5, "role_id": 52, "user": "admin", "role": "provincial_admin", "area": "梅州"}, {"user_id": 6, "role_id": 1, "user": "烟草科技", "role": "admin", "area": "梅州"}, {"user_id": 8, "role_id": 1, "user": "梅州烟草", "role": "admin", "area": "梅州"}, {"user_id": 9, "role_id": 1, "user": "云浮烟草", "role": "admin", "area": "云浮"}, {"user_id": 12, "role_id": 1, "user": "潮州烟草", "role": "admin", "area": "潮州"}, {"user_id": 20, "role_id": 2, "user": "test_normal", "role": "common", "area": "梅州"}, {"user_id": 21, "role_id": 2, "user": "test_other", "role": "common", "area": "梅州"} ] ``` --- ### 1.3 权限控制规则 #### 规则矩阵表 | 操作 | 省级管理员 | 市级管理员 | 普通用户 | |------|----------|----------|---------| | **查看角色列表** | ✅ 所有角色 | ✅ 所有角色 | ✅ 所有角色 | | **查看用户列表** | ✅ 所有地区用户 | ✅ 仅同地区用户 | ✅ 仅同地区用户 | | **分配用户角色** | ✅ 所有地区用户 | ✅ 仅同地区用户 | ❌ 无权限 | | **移除用户角色** | ✅ 所有地区用户 | ✅ 仅同地区用户 | ❌ 无权限 | | **修改角色权限** | ✅ 可以修改 | ❌ 无权限 | ❌ 无权限 | #### 地区隔离逻辑 **市级管理员的地区限制**: ```sql -- 示例:梅州市级管理员(area='梅州') -- 查看用户列表 SELECT * FROM sso_users WHERE status = 0 AND area = '梅州' -- ⭐强制过滤同地区 -- 分配用户角色(检查目标用户地区) SELECT area FROM sso_users WHERE id = $1 -- 如果 target_area != '梅州' → 返回403错误 -- 移除用户角色(检查目标用户地区) SELECT area FROM sso_users WHERE id = $1 -- 如果 target_area != '梅州' → 返回403错误 ``` --- ## 2. 完整接口文档 ### 2.1 角色管理接口 #### 2.1.1 获取角色列表 **接口地址**: ``` GET /api/v3/rbac/roles ``` **权限要求**: - 仅需登录(所有登录用户可访问) **请求参数**: | 参数名 | 位置 | 类型 | 必填 | 默认值 | 说明 | |-------|------|------|------|--------|------| | `page` | query | integer | 否 | 1 | 页码(从1开始) | | `page_size` | query | integer | 否 | 20 | 每页数量(1-100) | | `role_key` | query | string | 否 | - | 角色标识过滤(精确匹配) | | `role_name` | query | string | 否 | - | 角色名称模糊搜索 | | `include_system` | query | boolean | 否 | true | 是否包含系统角色 | **请求示例**: ```bash # 示例1:获取第1页,每页20条 curl -X GET "http://localhost:8073/api/v3/rbac/roles?page=1&page_size=20" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" # 示例2:搜索角色名称包含"管理"的角色 curl -X GET "http://localhost:8073/api/v3/rbac/roles?role_name=管理" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" # 示例3:查询特定角色 curl -X GET "http://localhost:8073/api/v3/rbac/roles?role_key=admin" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` **返回格式**: ```json { "total": 3, "page": 1, "page_size": 20, "data": [ { "id": 52, "role_key": "provincial_admin", "role_name": "省级管理员", "description": "拥有全部权限,可以管理所有地区的评查点规则", "is_system": true, "created_at": "2025-01-15 10:30:00", "updated_at": "2025-01-20 14:20:00", "user_count": 1, "permission_count": 128 }, { "id": 1, "role_key": "admin", "role_name": "市级管理员", "description": "负责本地区的所有业务管理,不包括系统设置和角色权限管理", "is_system": false, "created_at": "2025-01-10 09:00:00", "updated_at": "2025-01-18 16:45:00", "user_count": 4, "permission_count": 85 }, { "id": 2, "role_key": "common", "role_name": "普通员工", "description": "仅能操作自己的数据", "is_system": false, "created_at": "2025-01-10 09:05:00", "updated_at": "2025-01-15 11:30:00", "user_count": 2, "permission_count": 32 } ] } ``` **字段说明**: | 字段 | 类型 | 说明 | |------|------|------| | `total` | integer | 总记录数 | | `page` | integer | 当前页码 | | `page_size` | integer | 每页大小 | | `data` | array | 角色列表 | | `data[].id` | integer | 角色ID | | `data[].role_key` | string | 角色标识(唯一) | | `data[].role_name` | string | 角色名称 | | `data[].description` | string | 角色描述 | | `data[].is_system` | boolean | 是否系统角色 | | `data[].created_at` | string | 创建时间(北京时间) | | `data[].updated_at` | string | 更新时间(北京时间) | | `data[].user_count` | integer | 拥有该角色的用户数量 | | `data[].permission_count` | integer | 该角色拥有的权限数量 | **业务逻辑**: ``` 1. JWT Token验证 └─ 验证通过 → 解析用户信息 2. 构建查询条件 ├─ 如果提供 role_key → 添加精确匹配条件 ├─ 如果提供 role_name → 添加模糊搜索条件 └─ 如果 include_system=false → 过滤系统角色 3. ⭐核心逻辑:所有人看到所有角色 └─ 不进行用户角色过滤(角色是全局统一的) 4. 分页查询 ├─ OFFSET = (page - 1) * page_size └─ LIMIT = page_size 5. 统计额外信息 ├─ 查询每个角色的用户数量(COUNT) └─ 查询每个角色的权限数量(COUNT) 6. 返回结果 ``` **错误响应**: ```json { "detail": "Token已过期" } ``` --- ### 2.2 用户管理接口 #### 2.2.1 获取用户列表 **接口地址**: ``` GET /api/v2/users ``` **权限要求**: - 仅需登录 **请求参数**: | 参数名 | 位置 | 类型 | 必填 | 默认值 | 说明 | |-------|------|------|------|--------|------| | `page` | query | integer | 否 | 1 | 页码(从1开始) | | `page_size` | query | integer | 否 | 20 | 每页数量(1-100) | | `ou_id` | query | string | 否 | - | 组织单位ID过滤 | | `is_leader` | query | boolean | 否 | - | 是否为领导过滤 | | `status` | query | integer | 否 | 0 | 用户状态(0=正常) | | `search` | query | string | 否 | - | 搜索关键词(用户名或昵称) | **请求示例**: ```bash # 示例1:获取第1页用户 curl -X GET "http://localhost:8073/api/v2/users?page=1&page_size=20" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" # 示例2:搜索用户名或昵称包含"张"的用户 curl -X GET "http://localhost:8073/api/v2/users?search=张" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" # 示例3:查询特定部门的用户 curl -X GET "http://localhost:8073/api/v2/users?ou_id=0000000A1ML" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` **返回格式**: ```json { "users": [ { "id": 5, "username": "admin", "nick_name": "admin", "ou_id": "test", "ou_name": "test", "is_leader": false, "status": 0 }, { "id": 6, "username": "烟草科技", "nick_name": "烟草科技", "ou_id": "0000000A1ML", "ou_name": "测试技术部", "is_leader": false, "status": 0 } ], "total": 6 } ``` **业务逻辑**: ``` 1. JWT Token验证 └─ 解析用户角色(user_role)和地区(area) 2. ⭐核心逻辑:地区数据隔离 ├─ 如果 user_role == 'provincial_admin' │ └─ 查询所有地区用户(无地区过滤) └─ 否则(admin或其他用户) └─ 强制添加条件:WHERE area = current_user.area 3. 应用额外过滤条件 ├─ 如果提供 ou_id → 添加 ou_id = {ou_id} ├─ 如果提供 is_leader → 添加 is_leader = {is_leader} └─ 如果提供 search → 添加 (username ILIKE %{search}% OR nick_name ILIKE %{search}%) 4. 分页查询 ├─ OFFSET = (page - 1) * page_size └─ LIMIT = page_size 5. 查询总数(使用相同过滤条件) 6. 返回结果 ``` **地区过滤示例**: ```sql -- 省级管理员(user_role='provincial_admin') SELECT * FROM sso_users WHERE status = 0 -- 返回:所有地区的10个用户 -- 市级管理员(user_role='admin', area='梅州') SELECT * FROM sso_users WHERE status = 0 AND area = '梅州' -- 返回:仅梅州的6个用户 ``` --- ### 2.3 角色分配接口 #### 2.3.1 分配用户到角色 **接口地址**: ``` POST /api/v3/rbac/users/{user_id}/roles ``` **权限要求**: - 需要角色分配权限 **请求参数**: | 参数名 | 位置 | 类型 | 必填 | 说明 | |-------|------|------|------|------| | `user_id` | path | integer | 是 | 用户ID | | `role_ids` | body | array | 是 | 角色ID列表 | **请求示例**: ```bash # 给用户ID=20分配common角色(role_id=2) curl -X POST "http://localhost:8073/api/v3/rbac/users/20/roles" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "role_ids": [2] }' ``` **请求Body示例**: ```json { "role_ids": [2] } ``` **返回格式**: ```json { "code": 200, "msg": "success", "data": { "user_id": 20, "username": "test_normal", "assigned_roles": [ { "role_id": 2, "role_key": "common", "role_name": "普通员工" } ] } } ``` **业务逻辑**: ``` 1. JWT Token验证 └─ 解析当前用户角色(current_user_role)和地区(current_user_area) 2. 查询目标用户信息 └─ SELECT id, username, area FROM sso_users WHERE id = {user_id} 3. ⭐核心逻辑:地区检查 ├─ 如果 current_user_role == 'provincial_admin' │ └─ 跳过地区检查(可操作所有地区用户) └─ 否则(admin或其他用户) ├─ 如果 target_area != current_user_area │ └─ 返回403错误:"无权限给其他地区用户分配角色" └─ 否则,继续执行 4. 防止自己给自己分配角色 └─ 如果 user_id == current_user_id → 返回403错误 5. 验证角色是否存在 └─ SELECT * FROM roles WHERE id IN ({role_ids}) 6. 检查provincial_admin角色限制 └─ 只有省级管理员可以分配provincial_admin角色 7. 开始事务 ├─ 插入 user_role 记录(批量) └─ 提交事务 8. 返回结果 ``` **地区检查示例**: ```sql -- 场景1:梅州市级管理员(area='梅州')给梅州用户分配角色 target_user: {id: 20, area: '梅州'} current_user: {role: 'admin', area: '梅州'} 检查结果: '梅州' == '梅州' → ✅ 允许 -- 场景2:梅州市级管理员尝试给云浮用户分配角色 target_user: {id: 9, area: '云浮'} current_user: {role: 'admin', area: '梅州'} 检查结果: '云浮' != '梅州' → ❌ 返回403错误 ``` **错误响应**: ```json { "detail": "无权限给其他地区用户分配角色: target_area=云浮, your_area=梅州" } ``` --- #### 2.3.2 移除用户角色 **接口地址**: ``` DELETE /api/v3/rbac/users/{user_id}/roles/{role_id} ``` **权限要求**: - 需要角色分配权限 **请求参数**: | 参数名 | 位置 | 类型 | 必填 | 说明 | |-------|------|------|------|------| | `user_id` | path | integer | 是 | 用户ID | | `role_id` | path | integer | 是 | 角色ID | **请求示例**: ```bash # 移除用户ID=20的common角色(role_id=2) curl -X DELETE "http://localhost:8073/api/v3/rbac/users/20/roles/2" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` **返回格式**: ```json { "code": 200, "msg": "success", "data": { "user_id": 20, "role_id": 2, "message": "角色移除成功" } } ``` **业务逻辑**: ``` 1. JWT Token验证 2. 查询目标用户信息 └─ SELECT id, username, area FROM sso_users WHERE id = {user_id} 3. ⭐核心逻辑:地区检查(同分配用户逻辑) ├─ 省级管理员 → 无限制 └─ 市级管理员 → 只能操作同地区用户 4. 验证角色分配是否存在 └─ SELECT * FROM user_role WHERE user_id = {user_id} AND role_id = {role_id} 5. 删除角色分配 └─ DELETE FROM user_role WHERE user_id = {user_id} AND role_id = {role_id} 6. 返回结果 ``` --- ## 3. 业务场景示例 ### 场景1:梅州市级管理员给本地用户分配角色 **前置条件**: - 当前用户:梅州烟草(user_id=8, role=admin, area=梅州) - 目标用户:test_normal(user_id=20, area=梅州) **操作流程**: ```bash # 步骤1:查看所有角色 GET /api/v3/rbac/roles # 返回(所有人都能看到): { "data": [ {"id": 1, "role_key": "admin", "role_name": "市级管理员"}, {"id": 2, "role_key": "common", "role_name": "普通员工"}, {"id": 52, "role_key": "provincial_admin", "role_name": "省级管理员"} ] } # 步骤2:查看可分配的用户列表 GET /api/v2/users # 返回(只看到梅州的用户): { "users": [ {"id": 5, "username": "admin", "area": "梅州"}, {"id": 6, "username": "烟草科技", "area": "梅州"}, {"id": 8, "username": "梅州烟草", "area": "梅州"}, {"id": 19, "username": "test_admin", "area": "梅州"}, {"id": 20, "username": "test_normal", "area": "梅州"}, {"id": 21, "username": "test_other", "area": "梅州"} ], "total": 6 } # 步骤3:给test_normal分配common角色 POST /api/v3/rbac/users/20/roles { "role_ids": [2] } # 返回: { "code": 200, "msg": "success", "data": { "user_id": 20, "username": "test_normal", "assigned_roles": [ {"role_id": 2, "role_key": "common", "role_name": "普通员工"} ] } } # ✅ 成功!因为: # 1. 角色列表可见(所有人都能看到所有角色) # 2. 用户列表只显示梅州用户(地区过滤) # 3. 分配成功(同地区用户) ``` --- ### 场景2:梅州市级管理员尝试给云浮用户分配角色 **前置条件**: - 当前用户:梅州烟草(user_id=8, role=admin, area=梅州) - 目标用户:云浮烟草(user_id=9, area=云浮) **操作流程**: ```bash # 步骤1:查看用户列表 GET /api/v2/users # 返回(只看到梅州的6个用户,看不到云浮烟草): { "users": [ {"id": 5, "username": "admin", "area": "梅州"}, {"id": 6, "username": "烟草科技", "area": "梅州"}, ... ], "total": 6 } # 步骤2:尝试直接调用API给云浮用户分配角色 POST /api/v3/rbac/users/9/roles { "role_ids": [2] } # 返回: { "detail": "无权限给其他地区用户分配角色: target_area=云浮, your_area=梅州" } # ❌ 失败!因为: # 1. 地区检查:云浮 != 梅州 # 2. 后端强制拦截跨地区操作 ``` --- ### 场景3:省级管理员的完整权限 **前置条件**: - 当前用户:admin(user_id=5, role=provincial_admin, area=梅州) **操作流程**: ```bash # 步骤1:查看所有角色 GET /api/v3/rbac/roles # 返回(所有角色): { "data": [ {"id": 1, "role_key": "admin"}, {"id": 2, "role_key": "common"}, {"id": 52, "role_key": "provincial_admin"} ] } # 步骤2:查看所有用户(包括所有地区) GET /api/v2/users # 返回(所有地区的10个用户): { "users": [ {"id": 5, "area": "梅州"}, {"id": 6, "area": "梅州"}, {"id": 7, "area": "揭阳"}, {"id": 8, "area": "梅州"}, {"id": 9, "area": "云浮"}, {"id": 12, "area": "潮州"}, ... ], "total": 10 } # 步骤3:给云浮用户分配角色(跨地区) POST /api/v3/rbac/users/9/roles { "role_ids": [1] } # 返回: { "code": 200, "msg": "success" } # ✅ 成功!因为: # 1. 省级管理员可以看到所有地区用户 # 2. 省级管理员可以操作所有地区用户 ``` --- ## 4. 数据库实际数据 ### 4.1 角色数据 ```sql SELECT id, role_key, role_name, description FROM roles ORDER BY id; ``` | id | role_key | role_name | description | |----|----------|-----------|-------------| | 1 | admin | 市级管理员 | 负责本地区的所有业务管理 | | 2 | common | 普通员工 | 仅能操作自己的数据 | | 52 | provincial_admin | 省级管理员 | 拥有全部权限 | --- ### 4.2 用户数据(按地区分组) ```sql SELECT id, username, nick_name, area, ou_name FROM sso_users WHERE status = 0 ORDER BY area, id; ``` **梅州(6人)**: | id | username | nick_name | area | ou_name | |----|----------|-----------|------|---------| | 5 | admin | admin | 梅州 | test | | 6 | 烟草科技 | 烟草科技 | 梅州 | 测试技术部 | | 8 | 梅州烟草 | 梅州烟草 | 梅州 | 梅州管理员账号 | | 19 | test_admin | 测试管理员 | 梅州 | 测试部门 | | 20 | test_normal | 测试普通用户 | 梅州 | 测试部门 | | 21 | test_other | 测试其他用户 | 梅州 | 测试部门 | **云浮(2人)**: | id | username | area | |----|----------|------| | 9 | 云浮烟草 | 云浮 | | 22 | OAuth已存在用户测试 | 云浮 | **揭阳(1人)**、**潮州(1人)**... --- ### 4.3 用户角色分配数据 ```sql SELECT u.id as user_id, u.username, u.area, r.role_key, r.role_name FROM user_role ur JOIN sso_users u ON ur.user_id = u.id JOIN roles r ON ur.role_id = r.id WHERE u.status = 0 ORDER BY u.area, u.id; ``` | user_id | username | area | role_key | role_name | |---------|----------|------|----------|-----------| | 5 | admin | 梅州 | provincial_admin | 省级管理员 | | 6 | 烟草科技 | 梅州 | admin | 市级管理员 | | 8 | 梅州烟草 | 梅州 | admin | 市级管理员 | | 20 | test_normal | 梅州 | common | 普通员工 | | 21 | test_other | 梅州 | common | 普通员工 | | 9 | 云浮烟草 | 云浮 | admin | 市级管理员 | | 12 | 潮州烟草 | 潮州 | admin | 市级管理员 | --- ## 5. 前端对接指南 ### 5.1 角色权限管理页面 #### Vue 3 完整示例 ```vue ``` ### 5.2 关键要点 #### 1. Token解析 ```javascript // 解析JWT Token获取用户信息 const token = localStorage.getItem('token') const payload = JSON.parse(atob(token.split('.')[1])) // Payload包含: { user_id: 8, username: "梅州烟草", user_role: "admin", // 用户角色 area: "梅州", // 用户地区(⭐重要) exp: 1738036800 } ``` #### 2. 错误处理 ```javascript // 403错误:跨地区操作 if (response.status === 403) { ElMessage.error('权限不足:只能给同地区用户分配角色') } // 401错误:Token过期 if (response.status === 401) { ElMessage.error('登录已过期,请重新登录') router.push('/login') } ``` #### 3. 地区提示 ```javascript // 市级管理员登录时,提示当前地区 if (user_role === 'admin') { ElMessage.info(`您当前管理的地区:${area}`) } ``` --- ## 附录 ### A. 错误码对照表 | HTTP状态码 | 说明 | 常见原因 | 示例 | |-----------|------|---------|------| | 200 | 成功 | - | - | | 400 | 请求参数错误 | 参数格式不正确 | `{"detail": "role_ids必须是数组"}` | | 401 | 未认证 | Token无效或过期 | `{"detail": "Token已过期"}` | | 403 | 无权限 | 跨地区操作或权限不足 | `{"detail": "无权限给其他地区用户分配角色"}` | | 404 | 资源不存在 | 用户或角色不存在 | `{"detail": "用户不存在: user_id=999"}` | | 500 | 服务器错误 | 后端异常 | `{"detail": "数据库连接失败"}` | --- ### B. JWT Token规范 **Header格式**: ``` Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` **Payload字段**: | 字段 | 类型 | 必填 | 说明 | 示例 | |------|------|------|------|------| | `user_id` | integer | 是 | 用户ID | 8 | | `username` | string | 是 | 用户名 | 梅州烟草 | | `user_role` | string | 是 | 用户角色 | admin, provincial_admin, common | | `area` | string | 是 | 用户地区(⭐用于权限隔离) | 梅州, 云浮, 揭阳, 潮州 | | `exp` | integer | 是 | 过期时间(Unix时间戳) | 1738036800 | | `aud` | string | 是 | 受众标识 | docauditai | --- ### C. 数据库字段重要说明 | 字段 | 表 | 用途 | 示例 | 说明 | |------|-----|------|------|------| | `area` | sso_users | **地区隔离**(权限控制) | 梅州, 云浮 | ⭐用于判断市级管理员的操作范围 | | `ou_name` | sso_users | **部门划分**(组织结构) | 测试技术部, 研发部 | 仅用于显示,不用于权限控制 | | `ou_id` | sso_users | 组织单位ID | 0000000A1ML | 用于组织树结构 | **⚠️ 关键区别**: - `area`:用于**权限隔离**(省/市级别) - `ou_name`:用于**组织显示**(部门级别) --- ### D. 快速参考 #### 角色类型 | role_key | role_name | 说明 | |----------|-----------|------| | `provincial_admin` | 省级管理员 | 最高权限,可操作所有地区 | | `admin` | 市级管理员 | 地区管理员,只能操作同地区用户 | | `common` | 普通员工 | 基础权限 | #### API端点速查 | 接口 | 方法 | 说明 | |------|------|------| | `/api/v3/rbac/roles` | GET | 获取角色列表(所有人可见) | | `/api/v2/users` | GET | 获取用户列表(按地区过滤) | | `/api/v3/rbac/users/{id}/roles` | POST | 分配角色(地区检查) | | `/api/v3/rbac/users/{id}/roles/{rid}` | DELETE | 移除角色(地区检查) | --- **文档版本**: v3.3 **最后更新**: 2025-11-28 **维护者**: Backend Team **反馈渠道**: backend-team@example.com