在Vue 3应用中实现基于角色的访问控制(Role-Based Access Control, RBAC),是一种常见的权限管理方式。通过这种方式,我们可以确保用户只能访问与其角色相对应的功能或页面。以下将详细介绍如何在Vue 3项目中实现这一功能。
RBAC的核心思想是根据用户的“角色”来决定其可以访问的资源或执行的操作。例如,管理员可以访问所有页面和功能,而普通用户可能只能访问部分页面。在实现时,通常需要结合路由守卫、Vuex状态管理以及后端API接口来完成。
首先确保你的Vue 3项目已经创建好,并安装了vue-router
和pinia
(或者vuex
)。如果尚未安装,可以通过以下命令安装:
npm install vue-router pinia
假设后端提供了一个登录接口,登录成功后会返回用户的token及角色信息。示例返回数据如下:
{
"token": "your_jwt_token",
"role": "admin" // 或者 "user"
}
我们需要在前端存储这些信息以便后续使用。
创建一个Pinia store来保存用户的登录状态和角色信息。
// stores/user.js
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
token: null,
role: null,
}),
actions: {
setToken(token) {
this.token = token;
},
setRole(role) {
this.role = role;
},
logout() {
this.token = null;
this.role = null;
},
},
});
在登录逻辑中,调用此store来保存用户信息。
在vue-router
中定义多个页面,并为每个页面设置允许访问的角色。
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import AdminDashboard from '../views/AdminDashboard.vue';
import UserDashboard from '../views/UserDashboard.vue';
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: { roles: ['admin', 'user'] }, // 所有用户都可以访问
},
{
path: '/admin',
name: 'AdminDashboard',
component: AdminDashboard,
meta: { roles: ['admin'] }, // 只有管理员可以访问
},
{
path: '/user',
name: 'UserDashboard',
component: UserDashboard,
meta: { roles: ['user'] }, // 只有普通用户可以访问
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
通过路由守卫检查当前用户的角色是否符合目标页面的要求。
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { useUserStore } from './stores/user';
const app = createApp(App);
app.use(router);
router.beforeEach((to, from, next) => {
const userStore = useUserStore();
if (to.meta.roles) {
// 检查用户是否有权限访问目标页面
if (!to.meta.roles.includes(userStore.role)) {
alert('您没有权限访问该页面');
return next('/');
}
}
next();
});
app.mount('#app');
在登录页面中,调用后端接口获取用户信息,并将其保存到Pinia store中。
// views/Login.vue
<template>
<div>
<input v-model="username" placeholder="用户名" />
<input v-model="password" type="password" placeholder="密码" />
<button @click="login">登录</button>
</div>
</template>
<script>
import { ref } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';
import { useUserStore } from '../stores/user';
export default {
setup() {
const username = ref('');
const password = ref('');
const router = useRouter();
const userStore = useUserStore();
const login = async () => {
try {
const response = await axios.post('/api/login', {
username: username.value,
password: password.value,
});
const { token, role } = response.data;
// 保存用户信息
userStore.setToken(token);
userStore.setRole(role);
// 跳转到首页
router.push('/');
} catch (error) {
console.error(error);
alert('登录失败,请检查用户名和密码');
}
};
return { username, password, login };
},
};
</script>
如果某些页面的显示取决于用户的权限,可以在登录成功后动态添加路由:
function addDynamicRoutes(routes, userRole) {
if (userRole === 'admin') {
routes.push({
path: '/settings',
name: 'Settings',
component: () => import('@/views/Settings.vue'),
meta: { roles: ['admin'] },
});
}
}
然后在登录成功后调用此函数更新路由表。
除了路由级别的权限控制,还可以在组件内进行更细粒度的权限检查。例如,隐藏某些按钮或菜单项。
<template>
<div>
<button v-if="isAdmin">管理功能</button>
</div>
</template>
<script>
import { computed } from 'vue';
import { useUserStore } from '@/stores/user';
export default {
setup() {
const userStore = useUserStore();
const isAdmin = computed(() => userStore.role === 'admin');
return { isAdmin };
},
};
</script>
以下是整个权限控制流程的Mermaid代码表示:
sequenceDiagram participant User participant Vue participant Backend User->>Vue: 输入用户名和密码 Vue->>Backend: 发送登录请求 Backend-->>Vue: 返回token和角色 Vue->>Vue: 存储token和角色 Vue->>Vue: 检查路由权限 alt 有权限 Vue-->>User: 跳转到目标页面 else 无权限 Vue-->>User: 提示无权限并跳转到首页 end