Vue3 + TypeScript 企业级中后台权限系统实践
共 2214字,需浏览 5分钟
·
2026-07-27 18:49
在企业级管理后台里,权限控制是绕不开的核心功能。本文聊聊我在实际项目中落地的一套 RBAC 权限方案,覆盖 菜单级、按钮级、数据级 三层控制。
整体思路
- 后端返回当前用户的权限列表(角色 → 菜单权限、按钮权限、数据范围)
- 前端根据权限动态生成路由、控制按钮显隐、过滤接口请求
- 权限数据存入 Pinia store,全局注入自定义指令和组合式函数
1. 菜单级权限:动态路由
核心是让路由表按权限动态生成,而不是写死在 router 配置里。
// router/permission.ts
import type { RouteRecordRaw } from 'vue-router'
// 所有路由定义,带 meta.roles
const allRoutes: RouteRecordRaw[] = [
{ path: '/dashboard', meta: { title: '仪表盘', roles: ['admin', 'operator'] } },
{ path: '/inventory', meta: { title: '库存管理', roles: ['admin', 'warehouse'] } },
{ path: '/finance', meta: { title: '财务报表', roles: ['admin'] } },
]
export function filterRoutesByRoles(routes: RouteRecordRaw[], roles: string[]) {
return routes.filter(route => {
const routeRoles = route.meta?.roles as string[] | undefined
return !routeRoles || routeRoles.some(r => roles.includes(r))
})
}用户登录后调用 router.addRoute() 动态注册,侧边栏菜单也基于同一个过滤结果渲染。
2. 按钮级权限:自定义指令 + 组合式函数
页面上的按钮(新增、删除、审核等)按权限隐藏,用自定义指令最简洁:
// directives/permission.ts
import type { Directive } from 'vue'
import { useUserStore } from '@/stores/user'
export const vPermission: Directive = {
mounted(el, binding) {
const { value } = binding // 如 'inventory:delete'
const userStore = useUserStore()
if (!userStore.hasButtonPermission(value)) {
el.parentNode?.removeChild(el)
}
}
}使用时:<el-button v-permission="'inventory:delete'">删除</el-button>
更灵活的场景用组合式函数:
// composables/usePermission.ts
import { computed } from 'vue'
import { useUserStore } from '@/stores/user'
export function usePermission() {
const userStore = useUserStore()
const can = (perm: string) => computed(() => userStore.hasButtonPermission(perm))
return { can }
}3. 数据级权限:请求拦截器注入
不同角色看到的数据范围不同,比如普通操作员只能看自己仓库的库存。在 Axios 请求拦截器里统一处理:
// utils/request.ts
service.interceptors.request.use(config => {
const userStore = useUserStore()
if (config.url?.includes('/api/inventory/')) {
if (!userStore.isAdmin) {
config.params = { ...config.params, warehouseId: userStore.warehouseId }
}
}
return config
})前端控制只是第一层(用户体验),真正的安全依赖后端。
总结
- 菜单级用动态路由 + router.addRoute()
- 按钮级用自定义指令 v-permission
- 数据级用 Axios 拦截器注入过滤参数
- 权限数据统一走 Pinia store,登录后一次性加载
这套方案在多个实际项目中稳定运行,开发效率和可维护性都不错。欢迎交流你们是如何处理权限管理的。
评论
