我们将分几个步骤来实现这个功能:
- 定义角色和权限模型。
- 设置后端接口以获取用户信息。
- 使用 Vuex 管理用户状态。
- 配置 Vue Router 以实现动态路由加载。
- 创建动态菜单。
- 实现按钮级别的权限控制。
1. 角色和权限模型定义
首先,需要定义一个清晰的角色和权限模型。这通常涉及到以下几个概念:
- 角色 (Role) :
admin,editor,viewer等。 - 权限 (Permission) :每个角色可能拥有的具体权限,比如
viewDashboard,editArticle,deleteArticle,viewUsers,manageRoles等。 - 资源 (Resource) :可以是页面、API 或者按钮等。
2. 用户认证和授权
在实际应用中,通常需要有一个后端 API 来处理用户的登录认证和获取用户角色。一旦用户登录成功,他们的角色信息应该存储在本地(例如使用 Vuex 或 localStorage)。
示例:获取用户角色
// 假设我们有一个 API 接口来获取用户信息
async function fetchUserInfo() {
const response = await axios.get('/api/user/info');
return response.data;
}
# 或者
// mock.js
export async function fetchUserInfo() {
// 模拟从服务器获取用户信息
return {
id: 1,
username: 'admin',
roles: ['admin'],
permissions: ['viewDashboard', 'editArticle', 'deleteArticle', 'viewUsers', 'manageRoles'],
};
}
3. 使用 Vuex 管理用户状态
我们需要使用Vuex来存储和管理用户的信息和权限。(如登录状态、角色等)是一种很好的做法,这样可以方便地在整个应用中共享这些数据。
// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import { fetchUserInfo } from './mock';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
user: {},
permissions: [],
},
getters: {
isLoggedIn: state => !!state.user.id,
hasRole: state => role => state.user.roles.includes(role),
hasPermission: state => permission => state.permissions.includes(permission),
},
mutations: {
setUser(state, user) {
state.user = user;
},
setPermissions(state, permissions) {
state.permissions = permissions;
},
},
actions: {
async fetchUser({ commit }) {
const user = await fetchUserInfo();
commit('setUser', user);
commit('setPermissions', user.permissions);
},
},
});
4. 配置 Vue Router 以实现动态路由加载
Vue Router配置中,为每个路由添加一个元信息(meta)字段 来指定访问该路由所需的权限。同时使用Vue Router的全局前置守卫(beforeEach)来检查用户是否有访问当前路由所需的权限。
// router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import store from '../store';
6Vue.use(VueRouter);
const routes = [
{
path: '/',
component: () => import('../layout/MainLayout.vue'),
children: [
// 这里只定义了路由的基础结构,具体的权限会在下面进行动态添加
{
path: 'dashboard',
name: 'Dashboard',
component: () => import('../views/Dashboard.vue'),
meta: { requiresAuth: ['viewDashboard'] },
},
// 其他路由...
],
},
// 未授权路由
{
path: '/unauthorized',
name: 'Unauthorized',
component: () => import('../views/Unauthorized.vue'),
},
// 404 路由
{
path: '*',
redirect: { name: 'Unauthorized' },
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
router.beforeEach(async (to, from, next) => {
// 如果已经登录,则直接进入
if (store.getters.isLoggedIn) {
next();
} else {
// 尝试登录
await store.dispatch('fetchUser');
// 检查是否有权限访问目标路由
if (to.meta.requiresAuth) {
const hasPermission = to.meta.requiresAuth.some(permission => store.getters.hasPermission(permission));
if (hasPermission) {
next();
} else {
next({ name: 'Unauthorized' });
}
} else {
next();
}
}
});
export default router;
5. 创建动态菜单
在应用的主布局中添加动态生成的菜单项。
<!-- layout/MainLayout.vue -->
<template>
<div class="main-layout">
<nav>
<ul>
<li v-for="(item, index) in menuItems" :key="index" :class="{ active: $route.name === item.name }">
<router-link :to="item.path">{{ item.title }}</router-link>
</li>
</ul>
</nav>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {
menuItems: [
{ title: '仪表盘', path: '/dashboard', name: 'Dashboard', requiresAuth: ['viewDashboard'] },
// 其他菜单项...
],
};
},
computed: {
filteredMenuItems() {
return this.menuItems.filter(item => this.hasPermission(item.requiresAuth));
},
},
methods: {
hasPermission(permissions) {
return permissions.every(permission => this.$store.getters.hasPermission(permission));
},
},
};
</script>
6. 动态显示按钮和组件
为了动态地显示或隐藏某些按钮或组件,可以使用 Vue 的 v-if 或 v-show 指令来控制它们的可见性。
示例:动态显示按钮
<template>
<div>
<h1>仪表盘</h1>
<!-- 只有具备 'write' 权限的用户才能看到此按钮 -->
<button v-if="user.permissions.includes('write')">编辑</button>
<!-- 只有具备 'delete' 权限的用户才能看到此按钮 -->
<button v-if="user.permissions.includes('delete')">删除</button>
</div>
</template>
<script>
export default {
methods: {
hasPermission(permission) {
return this.$store.getters.hasPermission(permission);
},
},