Skip to content

权限控制

概述

本系统采用 菜单权限 + 按钮权限 的双层控制方案:

  • 菜单权限:通过后端返回的菜单数据控制可访问的页面(动态路由)
  • 按钮权限:通过权限标识字符串控制页面内按钮和操作的显隐

权限数据在用户登录后从后端获取,存储在 userStore.permissions 中。

权限指令

权限指令定义在 src/directives/perms.ts 中,提供两种指令:

v-has-perm(满足任一权限)

传入单个权限标识或权限数组,满足 任意一个 即显示元素(OR 关系):

vue
<!-- 单个权限 -->
<el-button v-has-perm="'admin.add'">新增管理员</el-button>

<!-- 多个权限,满足任一即可 -->
<el-button v-has-perm="['admin.edit', 'admin.update']">编辑</el-button>

v-has-all-perm(满足所有权限)

传入权限数组,必须 全部满足 才显示元素(AND 关系):

vue
<!-- 同时拥有 edit 和 audit 权限才显示 -->
<el-button v-has-all-perm="['order.edit', 'order.audit']">编辑并审核</el-button>

指令工作原理

权限指令通过设置 display: none 隐藏元素,并在权限变化时自动响应更新:

ts
// 核心检查逻辑
function checkPermission(permissions: string | string[], userStore: any): boolean {
    if (Array.isArray(permissions)) {
        return userStore.hasAnyPermission(permissions) // OR 关系
    } else {
        return userStore.hasPermission(permissions)    // 单个权限
    }
}

指令在 mounted 时注册对 userStore.permissionswatch,确保权限动态变化时 UI 自动更新。

向后兼容

系统同时注册了 v-permissionv-perms 作为 v-has-perm 的别名,旧代码无需迁移。

编程式权限检查

在需要在逻辑中(而非模板中)判断权限时,使用 userStore 提供的方法:

hasPermission(permission)

检查是否拥有 单个 权限:

ts
import { useUserStore } from '@/store'

const userStore = useUserStore()

if (userStore.hasPermission('admin.delete')) {
    // 执行删除操作
}

hasAnyPermission(permissions)

检查是否拥有权限列表中的 任意一个

ts
if (userStore.hasAnyPermission(['admin.edit', 'admin.update'])) {
    // 显示编辑按钮
}

hasAllPermissions(permissions)

检查是否 同时拥有 所有权限:

ts
if (userStore.hasAllPermissions(['order.edit', 'order.audit'])) {
    // 显示高级操作
}

超级管理员

当权限列表包含 *super_admin 时,所有权限检查均返回 true

ts
function hasPermission(permission: string): boolean {
    if (permissions.value.includes('*') || permissions.value.includes('super_admin')) {
        return true
    }
    return permissions.value.includes(permission)
}

按钮级权限控制完整示例

vue
<template>
    <div>
        <!-- 工具栏 -->
        <div class="toolbar">
            <el-button v-has-perm="'article.add'" type="primary" @click="handleAdd">
                新增文章
            </el-button>
            <el-button v-has-perm="'article.export'" @click="handleExport">
                导出
            </el-button>
        </div>

        <!-- 表格操作列 -->
        <el-table :data="list">
            <el-table-column label="操作">
                <template #default="{ row }">
                    <el-button v-has-perm="'article.edit'" link @click="handleEdit(row)">
                        编辑
                    </el-button>
                    <el-button v-has-perm="'article.delete'" link type="danger" @click="handleDelete(row)">
                        删除
                    </el-button>
                </template>
            </el-table-column>
        </el-table>
    </div>
</template>

<script setup lang="ts">
import { useUserStore } from '@/store'

const userStore = useUserStore()

// 编程式判断(例如控制整个区块的显隐)
const showAdvanced = computed(() => userStore.hasAllPermissions(['article.edit', 'article.audit']))
</script>

权限标识命名约定

权限标识由后端定义,建议采用 模块.操作 格式:

权限标识说明
admin.list查看管理员列表
admin.add新增管理员
admin.edit编辑管理员
admin.delete删除管理员
admin.status修改管理员状态

基于 MIT 许可发布