流程拆解

airsky 总索引 | 权限体系分析 索引

图清单

1. 接口权限校验流程

flowchart TD
  A[请求带 JWT 到达业务服务]
  B[取 TenantContext]
  C{未登录}
  D{tenant_id 为 0}
  E{是平台超管}
  F[查平台角色权限点]
  G{是超管或租户管理员}
  H[5 表 JOIN 校验权限点]
  P[放行]
  N[权限不足拒绝]

  A --> B --> C
  C -->|是| N
  C -->|否| D
  D -->|是 平台视角| E
  E -->|是| P
  E -->|否| F
  F --> P
  D -->|否 租户视角| G
  G -->|是| H
  G -->|否| H
  H --> P

说明:核心判定在 HasEffectivePermission。租户视角下普通用户走完整 5 表 JOIN;超管/租户管理员跳过角色判定但仍查租户菜单。全程无缓存,每请求实时查库。

代码锚点

  • 中间件入口:middleware/permission.go:13 RequirePermission
  • 核心判定:utils/rbac/permission.go:266 HasEffectivePermission
  • 平台角色权限点:utils/rbac/permission.go:73 hasPlatformRolePermission
  • 菜单交集:utils/rbac/permission.go:194 EffectiveMenuIDs

2. 数据权限过滤流程

flowchart TD
  Q[service 发起列表查询]
  S{是否挂 DataScopeFilter}
  SC[取用户最大 data_scope]
  D1[1 全部数据 不限制]
  D2[2 自定义部门 限部门列表]
  D3[3 本部门 限本部门]
  D4[4 本部门及以下 限部门子树]
  D5[5 仅本人 限创建人]
  NOW[现状 未挂 仅租户隔离]

  Q --> S
  S -->|已挂 理想态| SC
  SC --> D1
  SC --> D2
  SC --> D3
  SC --> D4
  SC --> D5
  S -->|未挂 实际态| NOW

说明:data_scope 数值越小权限越大(1 最大);多角色取最大范围。当前实际态是「未挂」分支,故数据权限未生效。

代码锚点

  • 过滤器:middleware/data_scope.go:18 DataScopeFilter
  • 最大范围:middleware/data_scope.go:55 getMaxDataScope
  • 子部门 BFS:middleware/data_scope.go:87 getChildDeptIDs
  • 未接入证据:pkg/DataScopeFilter 调用数为 0(仅 data_scope_test.go 使用)

3. 前端按钮级控制

v-permission 指令(directive/auth/permission.ts):检查 userStore.userInfo.permissions 是否含 *:*:* 或精确权限标识,不满足则 el.remove() 移除元素。hasPermission/hasAnyPermissionutils/permission.ts

注意:前端控制仅为 UX,真正安全边界在后端(后端已做)。

优化建议

P0 — 立即处理

  1. 接入数据权限(P0-2):在各域列表/详情查询的 GORM 链补 .Scopes(DataScopeFilter(tc, ownerField)),统一收口到 BaseService/查询 helper 避免逐个漏挂(漏挂即越权)。
  2. 权限缓存落地(P0-1):登录/切租户时一次性算出用户「有效权限集合」缓存到 Redis(按 userID+tenantID,TTL + 角色/菜单变更主动失效),中间件改为内存集合 O(1) 判断。复用已定义的 CacheKeyRoleMenus

P1 — 架构层

  1. 鉴权上移网关:粗粒度权限在网关统一做,业务服务只做细粒度数据权限,减少 322 次重复。
  2. DataScopeFilter N+1 治理getMaxDataScope/getCustomDeptIDs/getChildDeptIDs 每次过滤都查库,部门树、角色 data_scope 应随权限缓存一起设计。
  3. 前端 el.remove() 改造:用 display:none 或占位注释节点替代不可逆的 DOM 移除,避免 updated 重渲染失效。

P2 — 增强

  1. RBAC → ABAC/字段级:外贸场景常有「金额字段对销售脱敏」「合同价格仅财务可见」需求,可在 DTO 序列化层加字段级权限。
  2. 权限变更主动失效:引入缓存后配套「角色/菜单变更 → 清缓存」,sys_permission_audit_log 已记录变更事件,可作失效触发点。