63 lines
2.5 KiB
Markdown
63 lines
2.5 KiB
Markdown
# 9.7 权限控制
|
||
|
||
:::tip 概述
|
||
前端权限三层:**路由层**(菜单按角色过滤生成)、**指令层**(v-perm / v-perms 控制按钮)、**逻辑层**(usePermission 组合式函数供 v-if 使用)。超管通配码 `*:*:*` 全通过。
|
||
:::
|
||
|
||
## 指令
|
||
|
||
```html
|
||
<!-- 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)
|
||
|
||
```typescript
|
||
const { hasPermission, hasSomePermission, hasEveryPermission } = usePermission();
|
||
|
||
// v-if 场景
|
||
v-if="hasPermission(['sys:user:add'])"
|
||
```
|
||
|
||
| 函数 | 语义 |
|
||
|---|---|
|
||
| hasPermission(accesses) | 包含任一(空数组视为通过) |
|
||
| hasSomePermission(accesses) | 包含任一(string/array 归一) |
|
||
| hasEveryPermission(accesses) | 包含全部 |
|
||
|
||
## 权限数据来源
|
||
|
||
```text
|
||
登录后守卫 GetInfo → user store.getPermissions
|
||
(后端 LoadIdentity 装配的权限节点集合,含菜单下发的节点码)
|
||
```
|
||
|
||
## 安全边界提醒
|
||
|
||
前端权限**只是体验层**:隐藏按钮防误操作,越权请求仍会被后端 Authz 403 拦截。任何接口的安全性以 RouteSpec.Permission 为准,前端漏配指令不构成安全洞,但会造成用户困惑——两侧权限码保持一致是联调检查项(见 [3.9 权限节点配置](/zh/guide/permission.html))。
|
||
|
||
## 常见问题
|
||
|
||
| 现象 | 检查 |
|
||
|---|---|
|
||
| 按钮不显示 | 菜单节点码与 v-perm 值是否一致;角色是否勾选该节点 |
|
||
| 指令报错 | v-perm 需要字符串/数组,undefined 直接跳过 |
|
||
| 改授权后不生效 | 重新登录(权限集合在登录后装配) |
|
||
|
||
## 相关
|
||
|
||
- [5.4 权限管理(RBAC)](/zh/core/rbac.html)
|