前端组件级权限控制

前端组件级权限控制

组件级权限控制的核心思路是:先统一管理权限数据,再通过 "声明式" 或 "编程式" 的方式,在组件层面做权限校验。下面我会从核心方案、具体实现、最佳实践三个维度,给你讲清楚落地方式。

一、前置准备:权限数据的统一管理

无论哪种控制方式,第一步都是先把用户的权限数据规整好,这是所有组件权限控制的基础:

1、权限数据格式

javascript 复制代码
// 登录后从后端获取的用户权限数据(示例)

const userPermissions = {

 role: 'admin', // 角色:admin/editor/guest

 permissions: \['user:add', 'user:edit', 'user:delete', 'menu:report'], // 细粒度权限码

 menus: \['dashboard', 'user', 'report'] // 可访问的菜单标识

};

2、权限数据存储

  • 存入 Vuex/Pinia/Redux 等状态管理库(全局可访问);

  • 配合 localStorage/sessionStorage 做持久化(避免页面刷新丢失)。

二、组件级权限控制的 3 种核心方案(从易到难)

方案 1:指令式控制(推荐,适合按钮 / 小组件)

通过自定义指令(如v-permission),直接在组件标签上声明所需权限,无权限则隐藏 / 禁用组件,是最常用的方式。

以 Vue3 为例实现自定义权限指令:
javascript 复制代码
// src/directives/permission.js

import { useUserStore } from '@/stores/user'; // 引入状态管理的权限数据

// 自定义权限指令

export const permissionDirective = {

 mounted(el, binding) {

   const userStore = useUserStore();

   const requiredPerms = binding.value; // 获取指令传入的权限码(如\['user:delete'])

  

   // 校验权限:用户权限列表是否包含所需权限

   const hasPermission = requiredPerms.some(perm =>

     userStore.permissions.includes(perm)

   );

   // 无权限则移除组件(或禁用,根据需求调整)

   if (!hasPermission) {

     el.parentNode?.removeChild(el); // 彻底移除

     // 也可选择禁用:el.disabled = true; el.style.opacity = 0.5;

   }

 }

};

// 全局注册指令(main.js)

import { createApp } from 'vue';

import { permissionDirective } from '@/directives/permission';

const app = createApp(App);

app.directive('permission', permissionDirective);
使用方式(组件中):
javascript 复制代码
<template>

 <!-- 单个权限控制 -->

 <el-button v-permission="\['user:delete']">删除用户\</el-button>

 <!-- 多个权限满足其一即可 -->

 <el-button v-permission="\['user:add', 'admin']">新增/管理员专属\</el-button>

</template>

当然这是个侵入式的,会修改组件的内容。如果不想侵入,修改组件则可以使用方式2;

方案 2:组件封装式控制(适合通用权限组件)

封装一个<Permission>容器组件,内部做权限校验,只有满足权限才渲染子组件,适合复用性高的场景。

封装权限组件(Vue3):

src/components/Permission.vue

javascript 复制代码
<template>

 <slot v-if="hasPermission"></slot>

</template>

<script setup>

import { useUserStore } from '@/stores/user';

import { computed } from 'vue';

const props = defineProps({

 // 所需权限码/角色

 perms: {

   type: Array,

   required: true

 }

});

const userStore = useUserStore();

// 计算是否有权限

const hasPermission = computed(() => {

 return props.perms.some(perm =>

   userStore.permissions.includes(perm) || userStore.role === perm

 );

});

</script>
使用方式:
javascript 复制代码
<template>

 <Permission perms="\['user:edit']">

   <el-button>编辑用户\</el-button>

 </Permission>

 <!-- 角色控制 -->

 <Permission perms="\['admin']">

   <el-menu-item>管理员专属菜单\</el-menu-item>

 </Permission>

</template>
方案 3:编程式控制(适合复杂逻辑)

在组件的 JS 逻辑中直接判断权限,控制组件的显示 / 隐藏或功能执行,适合权限逻辑复杂的场景(如结合多个条件)。

示例(Vue3):
javascript 复制代码
<template>

 <el-button @click="handleDelete" v-if="canDelete">删除\</el-button>

</template>

<script setup>

import { useUserStore } from '@/stores/user';

import { computed } from 'vue';

const userStore = useUserStore();

// 编程式判断权限

const canDelete = computed(() => {

 // 复杂逻辑:管理员 且 有删除权限 且 不是只读模式

 return userStore.role === 'admin'

   && userStore.permissions.includes('user:delete')

   && !userStore.readonly;

});

const handleDelete = () => {

 // 再次校验(防止前端被篡改,双重保障)

 if (!canDelete.value) {

   ElMessage.error('无删除权限');

   return;

 }

 // 执行删除逻辑

};

</script>

三、进阶优化:避免前端权限被篡改

前端权限控制只是 "体验层",必须配合后端校验,否则用户可通过修改前端数据绕过权限:

  1. 接口层面:每个敏感接口(如删除、新增)都要校验用户权限,即使前端显示了按钮,无权限的请求后端也要返回 403;

  2. 权限数据加密 :从后端获取的权限数据可做简单加密 / 签名,前端校验前先验签,防止手动修改localStorage中的权限;

  3. 路由守卫兜底:即使组件级控制失效,路由守卫也要校验权限,避免无权限用户通过 URL 直接访问敏感页面。

四、不同框架的适配

  • React :无指令概念,优先用组件封装式(如<Permission perm="user:delete">)或 Hooks(usePermission('user:delete'));

  • Angular :通过*ngIf结合权限服务(permissionService.hasPerm('user:delete')),或自定义结构指令(类似 Vue 的自定义指令);

  • 原生 JS:通过 DOM 操作,先获取组件元素,再根据权限判断是否移除 / 禁用。

总结

  1. 核心方式:组件级权限控制优先用「自定义指令(Vue)/ 组件封装(React)」,复杂逻辑用编程式判断;

  2. 数据基础:先统一管理用户权限数据(角色 / 权限码),存入全局状态;

  3. 安全兜底:前端控制仅做体验优化,必须配合后端接口权限校验,防止篡改。