Skip to content

5.4 权限管理(RBAC) ​

概述

RBAC(基于角色的访问控制)链路:user →(user_role)→ role →(role_menu)→ menu(type=1 权限节点)。身份在 JWT 中间件加载(缓存 300s),权限判定在 Bind 包装层(HasPerm),前端按通配权限放开按钮。

RBAC 授权链路图 ​

text
请求 ──▶ JWT中间件 ──▶ LoadIdentity(userID)
                          │
            user ─────────┤ dept_id → DeptId(数据权限用)
            user_role ────┤ role.code → Roles[]
                          │ role.data_scope → DataScope(多角色取最宽松)
            role_menu ────┤
            menu(type=1,  ┤ permission → Perms[]
              status=0,   │
              hide=0) ────┘
                          ▼
            缓存 easygoadmin:user:identity:{uid} JSON TTL 300s
                          ▼
     Bind 包装层 HasPerm("sys:user:page"):
       permission=="" → 通过 │ Roles 含 ROLE_SUPER_ADMIN → 通过
       │ Perms 精确匹配 → 通过 │ 否则 403
     数据范围经 ctx(WithDataScope/WithDeptID)随行,在 applyFilters 末环过滤
     缓存失效:角色保存权限/改数据范围 / 用户分配角色/改部门 等主动 Del,过期兜底

身份加载(LoadIdentity,缓存 300s) ​

text
1) user 行回查 dept_id → DeptId(单列查询)
2) user_role → roleIds → role.code 集合(Roles)
   同一查询顺带读 role.data_scope:多角色取最宽松(数值 min,
   1 最宽 4 最严;缺列值按"全部"参与比较)→ DataScope
3) role_menu → menuIds → menu 中 type=1 且 status=0 且 hide=0 的
   permission 非空去重集合(Perms)
4) 超管/平台:DataScope 强制"全部"(过滤层另有 dataScopeBypass 双保险)

权限判定(consts.HasPerm) ​

text
判定顺序:
  1. permission 标签为空       → 通过(仅登录即可,如 /api/index/*)
  2. Roles 含 ROLE_SUPER_ADMIN → 通过(超管全放行)
  3. Perms 精确匹配            → 通过
  4. 否则                      → code=403 信封

权限码规范:sys:{模块小驼峰}:{action}
前端识别超管通配权限 *:*:*(getUser 返回)放开全部按钮权限。

权限点声明与管理 ​

环节实现
声明接口 gmeta permission:"sys:user:page" 标签
存储goframe_menu 表 type=1 行(permission 列)
创建生成器自动创建(7 固定 + status/import/export 按需)或菜单管理手工
分配角色管理勾选 → POST /api/role/menu/save 重写 role_menu + 清身份缓存
判定Bind 包装层 HasPerm(每请求)

角色管理扩展接口:

text
GET  /api/role/menu/list/:roleId  查询角色已勾选菜单(sys:role:getPermission)
POST /api/role/menu/save          重写 role_menu + 清理相关用户身份缓存
                                  (sys:role:savePermission)

菜单树:GetUserMenuTree 由 user→role→role_menu→menu 组装(index.GetMenus 消费);超管返回全量菜单。

缓存失效链 ​

text
身份缓存 easygoadmin:user:identity:{uid} 删除时机:
  * role.SavePermission → clearRoleIdentityCache(roleId)
    → 查该角色全部 user → 逐个 Del
  * role.Update(含 data_scope 变更)→ AfterUpdate → 同上
  * user.AssignRoles(user.Update/Add 均经此,改部门亦然)
    → clearIdentityCache(userId)
  * 兜底:300s 自然过期

前端配合 ​

  • 权限指令(directives/permission.ts)按 getUser 返回的 permissions 控制按钮显隐
  • 超管返回 *:*:*,指令识别通配直接放行
  • 后端不做按钮级校验——按钮级是前端 UX 控制,接口级是后端强制(新增接口必须声明 permission 或评审确认留空)

安全注意 ​

text
* hide=1 的权限节点不进 Perms——"禁用权限"用 status,不能用 hide
* 权限留空 = 登录即可,评审需明确该选择(新接口默认应声明权限)
* 身份缓存 300s 窗口内直接改库不会即时生效(API 路径均主动清缓存)
* 超管绕过全部权限校验——平台管理端点的收紧依赖节点设计

小蚂蚁云团队 · 提供技术支持