2.5 KiB
2.5 KiB
9.7 权限控制
:::tip 概述
前端权限三层:路由层(菜单按角色过滤生成)、指令层(v-perm / v-perms 控制按钮)、逻辑层(usePermission 组合式函数供 v-if 使用)。超管通配码 *:*:* 全通过。
:::
指令
<!-- ui/src/views/tool/example/index.vue 实际用法 -->
<el-button type="primary" @click="handleAdd" v-perm="['sys:example:add']">添加案例演示</el-button>
<el-button type="danger" @click="handleDelete()" v-perm="['sys:example:batchDelete']">批量删除</el-button>
| 指令 | 语义 | 实现 |
|---|---|---|
| v-perm | 包含其中任一权限(some 判定) | directives/permission.ts → hasSomePermission |
| v-perms | 包含全部权限(every 判定) | directives/permission.ts → hasEveryPermission |
判定基于 user store 的权限集合;命中通配码 *:*:* 直通(超管)。不满足时移除 DOM 元素(非隐藏)。
:::warning 入参必须是数组
hasSomePermission 对非数组入参按空权限处理(Array.isArray(accesses) ? accesses : [])——写成 v-perm="'sys:user:add'" 字符串形式会导致元素一律被移除。正确写法 v-perm="['sys:user:add']"。
:::
组合式函数(usePermission)
const { hasPermission, hasSomePermission, hasEveryPermission } = usePermission();
// v-if 场景
v-if="hasPermission(['sys:user:add'])"
| 函数 | 语义 |
|---|---|
| hasPermission(accesses) | 包含任一(空数组视为通过) |
| hasSomePermission(accesses) | 包含任一(string/array 归一) |
| hasEveryPermission(accesses) | 包含全部 |
权限数据来源
登录后守卫 GetInfo → user store.getPermissions
(后端 LoadIdentity 装配的权限节点集合,含菜单下发的节点码)
安全边界提醒
前端权限只是体验层:隐藏按钮防误操作,越权请求仍会被后端 Authz 403 拦截。任何接口的安全性以 RouteSpec.Permission 为准,前端漏配指令不构成安全洞,但会造成用户困惑——两侧权限码保持一致是联调检查项(见 3.9 权限节点配置)。
常见问题
| 现象 | 检查 |
|---|---|
| 按钮不显示 | 菜单节点码与 v-perm 值是否一致;角色是否勾选该节点 |
| 指令报错 | v-perm 需要字符串/数组,undefined 直接跳过 |
| 改授权后不生效 | 重新登录(权限集合在登录后装配) |