以下是基于 Vue2 实现的基础权限管理方案 ,涵盖路由权限控制、按钮权限控制、指令封装等核心功能,适合中小型后台系统:
一、权限数据设计
首先定义用户权限结构(通常从后端接口获取):
javascript
// src/store/modules/auth.js
const state = {
// 用户角色(如 ['admin', 'editor'])
roles: [],
// 用户拥有的权限码(如 ['user:add', 'user:edit'])
permissions: []
};
const mutations = {
SET_ROLES(state, roles) {
state.roles = roles;
},
SET_PERMISSIONS(state, permissions) {
state.permissions = permissions;
}
};
const actions = {
// 模拟从后端获取权限(实际项目中替换为接口请求)
getAuth({ commit }) {
return new Promise(resolve => {
// 假设后端返回的权限数据
const authData = {
roles: ['editor'],
permissions: ['dashboard:view', 'user:view', 'user:edit']
};
commit('SET_ROLES', authData.roles);
commit('SET_PERMISSIONS', authData.permissions);
resolve();
});
}
};
export default {
namespaced: true,
state,
mutations,
actions
};
二、路由权限控制
通过路由守卫 过滤无权限的路由,结合VueRouter的动态路由添加:
1. 定义路由规则(区分公开 / 私有路由)
javascript
// src/router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import store from '@/store';
Vue.use(Router);
// 公开路由(无需权限)
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login')
},
{
path: '/404',
component: () => import('@/views/404')
}
];
// 私有路由(需权限)
export const asyncRoutes = [
{
path: '/',
component: () => import('@/layout'),
redirect: '/dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard'),
meta: {
title: '首页',
roles: ['admin', 'editor'], // 需要的角色
permissions: ['dashboard:view'] // 需要的权限码
}
}
]
},
{
path: '/user',
component: () => import('@/layout'),
children: [
{
path: 'list',
component: () => import('@/views/user/list'),
meta: {
title: '用户列表',
permissions: ['user:view']
}
},
{
path: 'edit/:id',
component: () => import('@/views/user/edit'),
meta: {
title: '编辑用户',
permissions: ['user:edit']
}
}
]
},
{ path: '*', redirect: '/404', hidden: true }
];
const createRouter = () => new Router({
routes: constantRoutes
});
const router = createRouter();
export default router;
2. 路由守卫实现权限过滤
javascript
// src/permission.js
import router from './router';
import store from './store';
import { asyncRoutes, constantRoutes } from './router';
// 权限判断函数:检查是否有角色/权限
function hasPermission(roles, permissions, route) {
if (route.meta && route.meta.roles) {
// 角色校验
return roles.some(role => route.meta.roles.includes(role));
}
if (route.meta && route.meta.permissions) {
// 权限码校验
return permissions.some(perm => route.meta.permissions.includes(perm));
}
return true; // 无权限配置则默认可见
}
// 过滤私有路由
function filterAsyncRoutes(routes, roles, permissions) {
const res = [];
routes.forEach(route => {
const tmp = { ...route };
if (hasPermission(roles, permissions, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles, permissions);
}
res.push(tmp);
}
});
return res;
}
router.beforeEach(async (to, from, next) => {
// 模拟已登录(实际项目中用token判断)
const hasToken = true;
if (hasToken) {
if (to.path === '/login') {
next({ path: '/' });
} else {
// 判断是否已获取权限
const hasRoles = store.getters['auth/roles'].length > 0;
if (hasRoles) {
next();
} else {
try {
// 获取权限数据
await store.dispatch('auth/getAuth');
const roles = store.getters['auth/roles'];
const permissions = store.getters['auth/permissions'];
// 过滤并添加动态路由
const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles, permissions);
router.addRoutes(accessedRoutes);
// 确保路由添加完成后跳转
next({ ...to, replace: true });
} catch (err) {
next(`/login?redirect=${to.path}`);
}
}
}
} else {
// 未登录则跳转登录页
if (to.path === '/login') {
next();
} else {
next(`/login?redirect=${to.path}`);
}
}
});
三、按钮权限控制
通过自定义指令实现按钮级别的权限控制:
1. 注册权限指令
javascript
// src/directives/permission.js
import Vue from 'vue';
import store from '@/store';
/**
* v-permission: 按钮权限指令
* 使用:<button v-permission="'user:add'">新增</button>
*/
Vue.directive('permission', {
inserted(el, binding) {
const { value } = binding;
const permissions = store.getters['auth/permissions'];
// 校验权限(支持数组:v-permission="['user:add', 'user:edit']")
if (value) {
const hasPerm = Array.isArray(value)
? permissions.some(perm => value.includes(perm))
: permissions.includes(value);
if (!hasPerm) {
el.parentNode && el.parentNode.removeChild(el); // 无权限则移除元素
}
}
}
});
/**
* v-role: 角色权限指令
* 使用:<button v-role="'admin'">管理员按钮</button>
*/
Vue.directive('role', {
inserted(el, binding) {
const { value } = binding;
const roles = store.getters['auth/roles'];
if (value) {
const hasRole = Array.isArray(value)
? roles.some(role => value.includes(role))
: roles.includes(value);
if (!hasRole) {
el.parentNode && el.parentNode.removeChild(el);
}
}
}
});
2. 全局引入指令
javascript
// src/main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import './directives/permission'; // 引入权限指令
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app');
四、页面中使用权限控制
javascript
<!-- src/views/user/list.vue -->
<template>
<div>
<h1>用户列表</h1>
<!-- 按钮权限控制:只有user:add权限才显示 -->
<button v-permission="'user:add'">新增用户</button>
<!-- 角色控制:只有admin角色才显示 -->
<button v-role="'admin'">删除用户</button>
<!-- 表格内容 -->
<el-table :data="userList">
<el-table-column label="操作">
<template slot-scope="scope">
<!-- 编辑权限控制 -->
<el-button v-permission="'user:edit'" @click="editUser(scope.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
五、核心功能总结
- 路由权限 :通过
router.addRoutes动态添加有权限的路由,结合beforeEach守卫过滤无权限页面; - 按钮权限 :自定义
v-permission/v-role指令,无权限时自动移除 DOM 元素; - 权限存储:通过 Vuex 管理用户角色和权限码,支持从后端动态获取。
扩展建议
- 实际项目中,权限数据需从后端接口获取(如登录后返回);
- 可结合
vue-i18n实现权限相关文案的国际化; - 复杂场景可增加 "数据权限"(如用户只能查看自己创建的数据),通过接口参数过滤。
这套方案轻量且易扩展,适合 Vue2 项目的基础权限管理需求。