vue权限实现
Vue 权限实现方案
在 Vue 项目中实现权限控制通常涉及前端路由、按钮/组件级权限、动态菜单等方面。以下是几种常见的实现方式:
基于路由的权限控制
通过路由守卫拦截未授权访问,结合动态路由添加实现:
// router/index.js
router.beforeEach((to, from, next) => {
const hasToken = localStorage.getItem('token')
const userRoles = store.getters.roles // 假设从Vuex获取用户角色
if (to.meta.requiresAuth && !hasToken) {
next('/login')
} else if (to.meta.roles && !to.meta.roles.includes(userRoles)) {
next('/403') // 无权限页面
} else {
next()
}
})
动态添加路由示例:
// 过滤异步路由表
function filterAsyncRoutes(routes, roles) {
return routes.filter(route => {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
})
}
指令式按钮权限控制
通过自定义指令实现按钮级权限:
// main.js
Vue.directive('permission', {
inserted(el, binding) {
const { value } = binding
const permissions = store.getters.permissions
if (value && !permissions.includes(value)) {
el.parentNode && el.parentNode.removeChild(el)
}
}
})
使用方式:
<button v-permission="'user:delete'">删除用户</button>
组件级权限控制
封装权限校验组件:
// components/Permission.vue
export default {
props: {
required: {
type: [String, Array],
required: true
}
},
computed: {
hasPermission() {
const userPermissions = this.$store.getters.permissions
return Array.isArray(this.required)
? this.required.every(p => userPermissions.includes(p))
: userPermissions.includes(this.required)
}
},
render() {
return this.hasPermission ? this.$slots.default : null
}
}
使用方式:
<permission :required="['user:edit', 'user:view']">
<button>编辑用户</button>
</permission>
权限数据管理方案
-
权限数据结构:
// 后端返回的权限数据示例 { "roles": ["admin"], "permissions": ["user:add", "user:delete"], "menus": [ { "path": "/user", "meta": { "title": "用户管理" } } ] } -
Vuex存储方案:
// store/modules/permission.js export default { state: { roles: [], permissions: [], routes: [] }, mutations: { SET_ROLES(state, roles) { state.roles = roles }, SET_PERMISSIONS(state, permissions) { state.permissions = permissions }, SET_ROUTES(state, routes) { state.routes = routes } } }
动态菜单实现
根据权限生成菜单的两种方式:
-
前端过滤:
function filterMenus(menus, permissions) { return menus.filter(menu => { if (menu.children) { menu.children = filterMenus(menu.children, permissions) } return !menu.meta?.permission || permissions.includes(menu.meta.permission) }) } -
后端返回:
// 登录后获取菜单数据 async function getMenus() { const { data } = await api.getMenus() commit('SET_ROUTES', data) // 动态添加路由 data.forEach(route => { router.addRoute(route) }) }
最佳实践建议
- 权限校验应前后端配合,前端控制展示层,后端校验关键操作
- 敏感路由建议在后端进行二次校验
- 使用路由元信息(meta)存储权限标记
- 权限变更时需清除缓存并重新获取权限数据
- 生产环境建议将权限数据加密存储
以上方案可根据项目需求组合使用,中小型项目通常采用路由守卫+指令方式即可满足需求,复杂系统可能需要完整的动态路由+菜单方案。







