1. 页面概览
角色与权限页是 LightAIP 管理后台的 RBAC 治理入口,路由为 /admin/roles。它提供角色列表、新建/编辑/删除角色,以及权限配置弹窗——把表级、列级、行级三类权限(TABLE_ACCESS / COLUMN_ACCESS / ROW_LEVEL_FILTER)以勾选方式整体替换到角色。
页面聚焦"角色 = 权限集合"的模型:用户先挂角色(见「用户管理」),再在本页定义角色能访问哪些表、哪些列、受哪些行级过滤条件约束。一句话总结:角色与权限页是表/列/行三级权限的可视化配置台。
2. 访问入口
2.1 路由与菜单
| 项目 | 值 |
|---|---|
| 路由 path | /admin/roles(父路由 /admin) |
| 路由 name | AdminRoles |
| 路由 title | 角色与权限 |
| requiresAuth | true;父路由 meta requiresAdmin: true |
| 菜单位置 | Admin 后台菜单(AdminLayout.vue)「角色与权限」 |
| 前端源码 | action/web/src/views/RolesPage.vue |
| 路由注册 | action/web/src/router/index.js |
2.2 认证与权限
前端 /admin 父路由 requiresAdmin + 后端 adminMiddleware() 双重校验,非管理员不可达。请求经 action/web/src/api/aipClient.js(baseURL /aip-api/v1)附 localStorage.aip_token。
2.3 端口与 API 前缀
AIP 后端默认端口 18080,API 前缀 /aip-api,实际请求路径 /aip-api/v1/roles。
3. 界面布局
+--------------------------------------------------+
| 角色与权限 [新建角色] |
+--------------------------------------------------+
| [操作结果提示 alert(有消息时显示,可关闭)] |
+--------------------------------------------------+
| 角色列表(card) |
| 表格:ID | 角色名 | 权限数 | 操作 |
| 操作:[编辑][权限配置][删除] |
+--------------------------------------------------+
| 新建/编辑角色弹窗:角色名* |
| 删除确认弹窗:引用方用户清单 + 级联删除说明 + [确认删除] |
| 权限配置弹窗: |
| 提示:保存时将整体替换该角色全部权限 |
| 表级权限(TABLE_ACCESS)(n/m) [勾选列表] |
| 列级权限(COLUMN_ACCESS)(n/m) [勾选列表] |
| 行级权限(ROW_LEVEL_FILTER)(n/m) [勾选+过滤条件输入] |
+--------------------------------------------------+
各板块职责:
- 角色列表:全量角色表格,权限数列展示
(r.permissions || []).length。 - 新建/编辑角色:仅维护
role_name,权限另行配置。 - 权限配置弹窗:按权限类型分组的三段勾选区,行级权限额外提供过滤条件文本框(如
region = '华东')并做语法预校验(实时绿/红提示),底部「保存权限」整体替换。
4. 交互元素
| 控件 | 位置 | 含义与作用 |
|---|---|---|
| 新建角色按钮 | 页头 | 打开新建角色弹窗,角色名必填 |
| 编辑按钮 | 列表行 | 打开编辑弹窗改角色名(PUT /roles/:id) |
| 权限配置按钮 | 列表行 | 打开权限配置弹窗,加载 GET /roles/:id/permissions |
| 删除按钮 | 列表行 | 打开删除确认弹窗(先拉 GET /users 推导引用方清单),确认后 DELETE /roles/:id,不可撤销 |
| 删除确认弹窗(引用清单) | 覆盖层 | 展示正在引用该角色的用户名清单与数量(由 GET /users 返回的每用户 roles[].id 本地过滤得到,platform/domain/user.go:43-52、platform/domain/rbac.go:23-27);GET /users 失败时明确提示「无法确认引用方,删除后引用该角色的用户将失去权限」;弹窗常驻说明后端删除会级联清理该角色的权限/用户绑定/RLS 映射(platform/rbac/rbac_service.go:184-226),底部「确认删除」二次确认(2026-09-13 补) |
| 权限勾选框 | 权限弹窗 | 按 TABLE_ACCESS / COLUMN_ACCESS / ROW_LEVEL_FILTER 分组,组标题实时显示勾选数 |
| 行级过滤条件输入框 | 权限弹窗 | ROW_LEVEL_FILTER 项专属,填写 SQL 过滤条件(如 region = '华东'),预填原 filter_condition;实时语法预校验:合法显示绿色「✓ 语法预校验通过(以后端为准)」,非法输入框描红并提示具体位置/原因 |
| 保存权限按钮 | 权限弹窗 | 校验通过后把勾选集合构造成 {table, column, row} 全量 PUT,整体替换该角色全部权限;存在非法行级条件时阻止提交并提示 |
| 行级条件校验 | 权限弹窗 | 校验括号/引号配对、; 语句分隔符、首尾运算符、是否含比较运算符;空值视为未填写、不校验 |
5. 后端关联
5.1 端点表
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /roles | 全部角色列表 {roles: [...]} |
| POST | /roles | 创建角色,body {role_name}(不能为空) |
| PUT | /roles/:id | 更新角色名,body {role_name} |
| DELETE | /roles/:id | 删除角色,返回 {deleted: true};后端级联清理该角色的权限、用户-角色绑定与 RLS 策略映射(platform/rbac/rbac_service.go:184-226) |
| GET | /roles/:id/permissions | 角色权限(含 is_assigned 分配状态){permissions: [...]} |
| PUT | /roles/:id/permissions | 整体更新角色权限,body {table, column, row} |
| GET | /users | 删除前引用检查用:返回 {users:[...]},每个用户带 roles:[{id, role_name, permissions}](products/aip/server/handlers_admin.go:43-51、platform/domain/user.go:43-52);前端按 roles[].id 过滤出引用该角色的用户。后端无「按角色反查用户」的专用端点 |
5.2 关键机制
- 三级权限全量替换:保存时前端把勾选结果构造成
{table: [表名], column: {表: [列]}, row: {资源: 过滤条件}}提交,后端整体替换该角色全部权限(非增量合并)。 - 列级命名:COLUMN_ACCESS 的
resource_name形如表.列,前端按.拆分为{表: [列]};ROW_LEVEL_FILTER 以资源名为 key 携带过滤条件。 - 权限类型枚举:
permission_type取TABLE_ACCESS/COLUMN_ACCESS/ROW_LEVEL_FILTER三类,列表按此分组渲染并统计勾选数。 - 权限承载链路:角色权限经 RBAC 服务落库,用户在 NLQ 查询/执行时按角色生效(RLS/CLS 语义在查询侧应用)。
- 行级过滤条件字段与校验口径:请求体
RolePermissionsUpdate(action/platform/domain/rbac.go)的row为map[string]string(资源名 →filter_condition),后端UpdateRolePermissions(action/platform/rbac/rbac_service.go)以sql.NullString原样存储,不做任何解析/语法校验。因此前端实现的是 SQL WHERE 子句片段的保守预校验(非完整 SQL 解析),覆盖括号/引号配对、;、首尾运算符、比较运算符等常见错误;最终合法性以后端与数据库为准。
6. 权限与安全
- 前端
requiresAdmin+ 后端adminMiddleware()双重校验,普通用户接口返回 403。 - 角色 ID 为自增 uint,非数字路径参数返回 400;删除角色不可撤销,删除前弹窗展示引用方用户清单并要求二次确认(清单由前端拉
GET /users的roles[].id过滤得到;后端无专用反查端点,GET /users失败时降级为明确文案提示)。 - 行级过滤条件以文本形式保存并透传到查询侧;后端 RBAC 服务仅原样存储、不做语法/注入校验,前端为预校验(仅拦截明显语法错误,不能替代后端与查询侧的注入防护)。
7. 常见问题与排错
问题 1:权限配置弹窗显示"无可配置项"
现象:某分组无勾选项。
原因:数据库中尚未登记该类型的权限资源(permission_type 匹配不到行)。
处理:确认系统已初始化权限种子数据;表/列/行权限资源来自数据源元数据导入,先完成元数据导入。
问题 2:保存权限后之前勾选丢失
现象:再次打开权限配置,勾选状态与上次不同。
原因:保存是"整体替换"语义,未勾选即移除;或保存请求失败被回滚。
处理:确认提示"权限已保存(该角色全部权限已整体替换)";保存失败则查看 Network 中 PUT /roles/:id/permissions 响应。
问题 3:行级过滤条件没生效
现象:勾选了 ROW_LEVEL_FILTER 并填了条件,但查询未按行过滤。
原因:条件可能未随资源名提交(row[it.resource_name] 为空时回退 filter_condition),或该角色未挂到用户。
处理:重新打开权限配置确认条件已预填;确认用户在「用户管理」中已分配该角色;保存前前端会做语法预校验,若输入框描红请按提示修正;条件本身正确时到后端验证 RLS 策略解析。
8. 已知缺陷与边界
| 项 | 说明 |
|---|---|
| 全量替换 | 权限保存为整体替换,多人并行编辑会互相覆盖 |
| 无权限模板 | 新建角色需逐项勾选,无复制/模板能力 |
| 条件校验为预校验 | 行级过滤条件已有前端语法预校验(括号/引号配对、;、首尾运算符、比较运算符),但为保守预校验、非完整 SQL 解析,后端不做校验,最终以后端/数据库为准 |
| 角色引用检查(已于 2026-09-13 补齐,非专用端点) | 删除角色现在会先展示引用方用户清单并二次确认。清单并非来自「按角色反查用户」的专用端点(后端无该端点),而是前端拉取 GET /users 后用每个用户的 roles[].id 本地过滤得到(platform/domain/user.go:43-52);用户量很大时该请求为全量拉取,且 GET /users 失败时只能降级为「无法确认引用方,删除后引用该角色的用户将失去权限」的文案提示。后端删除本身会级联清理 role_permissions/user_roles/role_rls_policies(platform/rbac/rbac_service.go:184-226),因此不会留下孤儿绑定,但被解除引用的用户会立即失去该角色权限 |