9.7 权限控制
概述
前端权限是按钮级 UX 控制:directives/permission.ts 按 getUser 返回的 permissions 数组控制元素显隐;超管通配权限 *:*:* 直接放行。后端接口级校验是强制层(403),前端指令只是体验层。
权限数据流
text
登录 → GetInfo(/api/index/getUser)
→ userInfo.permissions(后端 LoadIdentity 的 Perms)
超管 = ["*:*:*"](通配)
→ store 缓存 → 指令消费后端 Perms 来源:role_menu → menu(type=1 且 status=0 且 hide=0)的 permission 去重集合(详见 5.4 权限管理(RBAC))。
指令用法(directives/permission.ts)
text
按钮级控制(语义示意):
<el-button v-permission="'sys:user:add'">新增</el-button>
指令逻辑:
permissions 含 "*:*:*" → 放行(超管)
permissions 含传入权限码 → 放行
否则 → 移除元素(v-if 等效)前后端权限对照(联调要点)
text
后端 gmeta permission:"sys:user:add"
↔ 前端指令 v-permission="'sys:user:add'"
↔ 菜单权限节点 permission=sys:user:add
↔ 角色已勾选该节点
四处必须一致——不一致的表现:
前端可见按钮但后端 403 → 节点存在但角色未勾选(或身份缓存旧)
前端按钮消失但后端有权限 → permissions 缓存旧 / 指令码拼错双重校验的定位
| 层 | 位置 | 性质 |
|---|---|---|
| 前端指令 | v-permission | UX 控制(防误操作、界面简洁)——可被绕过 |
| 后端校验 | Bind 包装层 HasPerm | 强制安全(403 拒绝)——唯一真值 |
定位认知
前端权限不是安全边界。绕过前端直接调接口的请求由后端 403 拦截。新增接口必须声明 gmeta permission(或评审确认留空=登录即可)。
菜单与按钮的分层
text
菜单(type=0):控制"页面能否访问"(路由生成层面)
按钮(type=1 权限节点):控制"页面内操作能否看到"(指令层面)
getUser.permissions 下发权限码集合;菜单树不含按钮节点开发规约
- 页面按钮逐个对齐 gmeta permission 码(复制粘贴防拼错)
- 新增权限码流程:gmeta 声明 → 菜单建节点 → 角色勾选 → 指令引用
- 不要发明前端私有权限码(必须与后端节点一致才有意义)
- 超管测试:admin 账号应看到全部按钮(
*:*:*放行) - 权限变更后重新登录验证(身份缓存 300s;前端 GetInfo 在登录/刷新时拉取)