菜单与按钮权限
Forge 前端通过动态路由和权限指令实现菜单级和按钮级权限控制。你需要理解权限的运作方式来正确控制页面元素的显示。
权限层级
| 层级 | 控制方式 | 说明 |
|---|---|---|
| 菜单权限 | 动态路由 | 用户能看到哪些菜单 |
| 接口权限 | @SaCheckPermission | 后端控制接口能否访问 |
| 按钮权限 | v-permission 指令 | 页面内按钮显示/隐藏 |
菜单权限
菜单从后端接口加载,根据当前用户角色动态生成路由:
typescript
// permission store 中生成路由
async function generateRoutes() {
const res = await getMenus()
const routes = filterAsyncRoutes(res.data)
routes.forEach(route => router.addRoute(route))
return routes
}未授权的菜单不会出现在侧边栏中,直接访问 URL 也会被路由守卫拦截。
按钮权限
v-permission 指令
vue
<template>
<!-- 有权限才显示 -->
<NButton v-permission="'biz:order:add'" @click="handleAdd">新增</NButton>
<!-- 无权限时隐藏 -->
<NButton v-permission="'biz:order:remove'" @click="handleDelete">删除</NButton>
</template>usePermission 组合式函数
javascript
import { usePermission } from '@/composables/usePermission'
const { hasPermission } = usePermission()
// 条件判断
const canEdit = computed(() => hasPermission('biz:order:edit'))
const canDelete = computed(() => hasPermission('biz:order:remove'))vue
<template>
<a v-if="canEdit" class="text-primary" @click="handleEdit">编辑</a>
<a v-if="canDelete" class="text-error" @click="handleDelete">删除</a>
</template>多权限判断
javascript
// 满足任意一个权限
const canManage = computed(() =>
hasPermission('biz:order:add') || hasPermission('biz:order:edit')
)
// 满足全部权限
const canAudit = computed(() =>
hasPermission('biz:order:add') && hasPermission('biz:order:audit')
)权限标识命名
权限标识与后端 @SaCheckPermission 注解值保持一致:
| 格式 | 示例 |
|---|---|
模块:业务:操作 | biz:order:add |
模块:业务:操作 | system:user:remove |
| 操作 | 标识 |
|---|---|
| 查询 | list / query |
| 新增 | add |
| 修改 | edit |
| 删除 | remove |
| 导出 | export |
| 导入 | import |
菜单过滤
typescript
function filterAsyncRoutes(routes: RouteRecordRaw[], roles: string[]) {
const result: RouteRecordRaw[] = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
result.push(tmp)
}
})
return result
}AiCrudPage 权限控制
javascript
const apiConfig = {
page: 'GET@/biz/order/page', // 需 biz:order:list
get: 'GET@/biz/order/:id', // 需 biz:order:query
add: 'POST@/biz/order', // 需 biz:order:add
edit: 'PUT@/biz/order', // 需 biz:order:edit
delete: 'DELETE@/biz/order/:id' // 需 biz:order:remove
}
const schema = computed(() => [
// 操作列按钮根据权限自动显示/隐藏
{ field: 'actions', label: '操作', component: 'AiTableActions' }
])注意事项
- 前端权限控制只是隐藏 UI,真正的安全防线在后端
@SaCheckPermission - 权限标识必须前后端一致
- 按钮权限优先用
v-permission指令,比v-if更简洁 - 菜单路由从后端加载,不在前端代码中硬编码
