签入版本
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# 9.7 权限控制
|
||||
|
||||
:::tip 概述
|
||||
前端权限控制通过 `v-perm` / `v-perms` 指令实现按钮级权限控制。
|
||||
前端权限控制通过 `v-perm` / `v-perms` 指令实现按钮级权限控制。**前端权限只是体验层**(隐藏按钮),真正的安全防线是后端 `#[Permission]` 注解 + `auth.jwt` 中间件。
|
||||
:::
|
||||
|
||||
## 权限指令
|
||||
@@ -11,7 +11,7 @@
|
||||
```vue
|
||||
<template>
|
||||
<!-- 只有拥有 sys:user:add 权限的用户才能看到此按钮 -->
|
||||
<el-button v-perm="'sys:user:add'" type="primary">新增</el-button>
|
||||
<el-button v-perm="['sys:user:add']" type="primary">新增</el-button>
|
||||
</template>
|
||||
```
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
## 指令实现
|
||||
|
||||
```typescript
|
||||
// src/directives/permission.ts
|
||||
// ui/src/directives/permission.ts
|
||||
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
|
||||
@@ -35,12 +35,16 @@ export const perm: ObjectDirective = {
|
||||
mounted(el: HTMLButtonElement, binding) {
|
||||
const { hasSomePermission } = usePermission();
|
||||
if (!hasSomePermission(binding.value)) {
|
||||
el.parentNode.removeChild(el); // 无权限则移除元素
|
||||
el.parentNode.removeChild(el); // 无权限则移除元素(非隐藏)
|
||||
}
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
:::tip 移除而非隐藏
|
||||
无权限时元素直接从 DOM **移除**(而非 `display:none`)——避免通过开发者工具看到"隐藏"的敏感操作按钮。
|
||||
:::
|
||||
|
||||
## usePermission Hook
|
||||
|
||||
:::tip 超级管理员
|
||||
@@ -48,7 +52,7 @@ export const perm: ObjectDirective = {
|
||||
:::
|
||||
|
||||
```typescript
|
||||
// src/hooks/web/usePermission.ts
|
||||
// ui/src/hooks/web/usePermission.ts
|
||||
|
||||
export function usePermission() {
|
||||
const userStore = useUserStore();
|
||||
@@ -73,7 +77,7 @@ export function usePermission() {
|
||||
|
||||
## 权限数据来源
|
||||
|
||||
用户登录后,`/index/getUser` 接口返回权限列表:
|
||||
用户登录后,`GET /api/index/getUser` 接口返回权限列表(`IndexService::getUser` → `JwtService::getUserPermissions`,与后端鉴权同一缓存):
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -82,10 +86,30 @@ export function usePermission() {
|
||||
"sys:user:add",
|
||||
"sys:user:update",
|
||||
"sys:user:delete",
|
||||
"sys:role:page",
|
||||
"..."
|
||||
"sys:role:page"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
超级管理员返回 `["*:*:*"]`,拥有所有权限。
|
||||
超级管理员返回 `["*:*:*"]`,拥有所有权限。
|
||||
|
||||
## 权限码对应关系
|
||||
|
||||
| 端 | 机制 | 示例 |
|
||||
|----|------|------|
|
||||
| 后端 | `#[Permission('sys:user:add', '添加用户')]` 注解 + 中间件反射鉴权 | 403 拦截 |
|
||||
| 前端 | `v-perm="['sys:user:add']"` 指令 | 按钮移除 |
|
||||
| 菜单 | `laravel_menu.permission` 字段(type=1 权限节点) | 角色树勾选 |
|
||||
|
||||
三处权限码必须**完全一致**(`sys:{模块}:{操作}`)。
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 现象 | 原因 | 处理 |
|
||||
|------|------|------|
|
||||
| 按钮不显示但接口可调 | 角色有权限码但 `getUser` 未返回 | 重新登录刷新权限缓存 |
|
||||
| 按钮显示但接口 403 | 菜单 permission 与注解不一致 | 逐字符比对权限码 |
|
||||
| 超管按钮仍隐藏 | permissions 未含 `*:*:*` | 检查 `getUser` 返回(uid=1 应为通配) |
|
||||
| 修改角色权限后前端无变化 | 前端权限缓存在 Store | 重新登录或刷新页面 |
|
||||
|
||||
详见 [5.4 权限管理(RBAC)](/zh/core/rbac.html)。
|
||||
|
||||
Reference in New Issue
Block a user