在 Vue 项目中如何实现 RBAC 角色权限控制 ,可以从 前端架构、权限存储、路由守卫、指令控制、组件封装等方面 进行详细阐述。
1. RBAC 角色权限模型
RBAC(基于角色的访问控制)通常有以下几层:
- 用户(User) :每个用户都有一个或多个角色。
- 角色(Role) :角色定义了一组权限。
- 权限(Permission) :具体的操作权限,比如
"view_dashboard"
、"edit_user"
。
在 Vue 前端,我们会从后端获取当前用户的角色和权限,然后:
- 动态控制路由(哪些页面可以访问)。
- 控制 UI 元素(按钮、菜单、表单项的显示)。
- 支持多角色(如 admin、editor、user) 。
2. Vue 前端权限存储
(1)用户角色 & 权限存储
在 Vuex / Pinia 里存储用户角色和权限,方便全局访问。
📌 使用 Pinia
// store/user.js
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => ({
roles: [], // 用户角色,例如 ["admin"]
permissions: [] // 具体权限,例如 ["view_dashboard", "edit_user"]
}),
actions: {
setUserRoles(roles) {
this.roles = roles;
},
setUserPermissions(permissions) {
this.permissions = permissions;
}
}
});
📌 作用:
- 用户登录后,从后端获取 角色 & 权限,存入
Pinia
。 - 其它组件可以直接访问
userStore.roles
和userStore.permissions
。
3. 路由权限控制
(1)前端路由配置
Vue 使用 vue-router
,我们可以通过 meta 字段 设置哪些角色可以访问某个页面。
// router/index.js
import { createRouter, createWebHistory } from "vue-router";
import { useUserStore } from "@/store/user";
const routes = [
{
path: "/dashboard",
component: () => import("@/views/Dashboard.vue"),
meta: { roles: ["admin", "editor"] } // 只有 admin 和 editor 能访问
},
{
path: "/user",
component: () => import("@/views/User.vue"),
meta: { roles: ["admin"] } // 只有 admin 能访问
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
// 全局路由守卫
router.beforeEach((to, from, next) => {
const userStore = useUserStore();
const userRoles = userStore.roles;
if (to.meta.roles && !userRoles.some(role => to.meta.roles.includes(role))) {
next("/403"); // 无权限跳转到403页面
} else {
next();
}
});
export default router;
📌 作用:
meta.roles
限定角色访问权限。beforeEach
守卫拦截 无权限用户 并跳转到 403 页面。
4. 自定义指令控制 UI 权限
我们可以用 v-permission
指令控制 按钮 / 菜单 / UI 组件。
(1)定义 v-permission
指令
// directives/permission.js
import { useUserStore } from "@/store/user";
export default {
mounted(el, binding) {
const userStore = useUserStore();
const permissions = userStore.permissions;
const requiredPermission = binding.value;
if (!permissions.includes(requiredPermission)) {
el.parentNode && el.parentNode.removeChild(el); // 无权限则删除元素
}
}
};
(2)在 main.js
中注册
import { createApp } from "vue";
import App from "./App.vue";
import permissionDirective from "./directives/permission";
const app = createApp(App);
app.directive("permission", permissionDirective);
app.mount("#app");
(3)在组件中使用
<button v-permission="'delete_user'">删除用户</button>
📌 效果:
- 如果用户 没有
delete_user
权限,按钮不会显示。
5. 角色权限动态渲染菜单
菜单项应该根据用户角色动态渲染。
<template>
<ul>
<li v-if="hasPermission('view_dashboard')">仪表盘</li>
<li v-if="hasPermission('manage_users')">用户管理</li>
</ul>
</template>
<script setup>
import { useUserStore } from "@/store/user";
const userStore = useUserStore();
const hasPermission = (perm) => {
return userStore.permissions.includes(perm);
};
</script>
📌 效果:
- 菜单项 只有用户 拥有相应权限 时才会渲染。
6. 角色权限管理后台
在 后端管理页面,可以动态配置角色的权限,并存入数据库:
<template>
<h3>角色管理</h3>
<ul>
<li v-for="role in roles" :key="role">
<span>{{ role }}</span>
<button @click="setPermissions(role)">设置权限</button>
</li>
</ul>
</template>
<script setup>
import { ref } from "vue";
const roles = ref(["admin", "editor", "user"]);
const setPermissions = (role) => {
console.log("修改权限:", role);
// 这里可以调用后端 API 修改权限
};
</script>
📌 效果:
- 管理后台可以修改角色权限,前端根据 最新权限 渲染 UI。
7. 结合后端的 API
前端在用户登录后,调用 API 获取用户权限:
// 登录后获取权限
async function fetchUserData() {
const res = await fetch("/api/user-info"); // 假设后端返回 { roles: ['admin'], permissions: ['view_dashboard', 'edit_user'] }
const data = await res.json();
userStore.setUserRoles(data.roles);
userStore.setUserPermissions(data.permissions);
}
📌 这样即使后端修改了角色权限,前端也能实时更新!
8. 总结
功能 | 实现方式 |
---|---|
存储用户权限 | Pinia (roles & permissions ) |
路由权限控制 | router.beforeEach() 拦截 |
UI 权限控制 | v-permission 指令 |
菜单权限控制 | v-if="hasPermission()" 动态渲染 |
后端 API 支持 | 登录时获取 roles & permissions |
✅ 前端基于 RBAC 的权限管理思路:
- 后端返回角色 & 权限。
- 存入 Pinia,前端全局可用。
- 路由守卫控制页面访问。
- 指令 &
v-if
控制 UI。 - 动态管理权限,前端自动适应。
🚀 这样即使后端修改了角色权限,前端也能实时更新 UI & 路由!