前端权限控制全方案解析
·
前言
在项目中,一些功能涉及重要的数据管理,为了确保数据安全,我们需要加入权限机制来限制用户操作。作为前端,我们的职责是配合后端提供的权限数据,在页面上实现各种权限限制。
需求分析
在实际业务中,主要需要在两个地方进行权限控制:
-
侧边菜单栏 - 控制菜单项的显示与隐藏
-
页面内操作 - 控制按钮、弹窗等元素的权限
问题识别
通过分析实际场景,主要面临以下问题:
-
权限数据的获取时机和存储位置
-
路由访问权限的限制
-
重定向逻辑处理
-
侧边菜单显示控制
-
团队协作的权限部署方案
解决方案
1. 权限获取与存储
在路由守卫中获取权限数据,存储在 Vuex 中:
javascript
// router.beforeEach 中的权限验证
router.beforeEach(async (to, from, next) => {
// 如果未获取权限列表,则先获取
if (!store.getters.getPermissionList.length) {
await store.dispatch('getPermissionList')
}
const permissionList = store.getters.getPermissionList
const { meta } = to
// 如果路由需要权限且用户无权限,则跳转无权限页面
if (meta && meta.permission && !hasPermission(permissionList, meta.permission)) {
next('/no-permission')
} else {
next()
}
})
// 权限验证方法
function hasPermission(permissionList, permission) {
if (Array.isArray(permission)) {
return permission.some(item => permissionList.includes(item))
}
return permissionList.includes(permission)
}
2. 路由配置与权限设置
在路由配置中通过 meta 字段定义权限要求:
javascript
const routes = [
{
path: '/drug',
name: '药品管理',
meta: { permission: ['drug_manage'] },
children: [
{
path: 'in',
name: '入库管理',
meta: { permission: ['drug_in'] }
},
{
path: 'out',
name: '出库管理',
meta: { permission: ['drug_out'] }
}
]
}
]
3. 动态重定向解决方案
为了解决权限动态变化导致的重定向问题,利用 Vue Router 的动态重定向功能:
javascript
// 动态重定向生成器
function createDynamicRedirect(routeConfig) {
return function(to) {
const permissionList = store.getters.getPermissionList
const firstPermissionChild = routeConfig.children.find(child =>
!child.meta?.permission || hasPermission(permissionList, child.meta.permission)
)
return firstPermissionChild ? firstPermissionChild.path : '/no-permission'
}
}
// 路由配置示例
{
path: '/drug',
redirect: createDynamicRedirect(routeConfig)
}
递归处理路由配置的完整方案:
javascript
function processRouterConfig(routes) {
return routes.map(route => {
if (route.children && route.children.length > 0) {
// 处理子路由
route.children = processRouterConfig(route.children)
// 如果没有设置 redirect,自动设置动态重定向
if (!route.redirect) {
route.redirect = createDynamicRedirect(route)
}
}
return route
})
}
// 应用配置
const finalRoutes = processRouterConfig(originalRoutes)
4. 侧边栏显示控制
将处理后的路由配置存储到 Vuex,侧边栏基于处理后的配置渲染:
javascript
// 处理侧边栏显示逻辑
function generateSidebarRoutes(routes, permissionList) {
return routes.filter(route => {
// 无权限要求或有权限则显示
if (!route.meta?.permission || hasPermission(permissionList, route.meta.permission)) {
// 处理子菜单
if (route.children) {
route.children = generateSidebarRoutes(route.children, permissionList)
// 如果所有子项都无权限,则不显示父级
return route.children.length > 0
}
return true
}
return false
})
}
5. 团队权限部署方案
提供多种权限控制方式,方便团队成员使用:
方法一:权限验证方法
javascript
// Vue 原型上挂载权限验证方法
Vue.prototype.$permission = function(permission) {
const permissionList = this.$store.getters.getPermissionList
return hasPermission(permissionList, permission)
}
// 在组件中使用
export default {
methods: {
handleOperation() {
if (this.$permission('operation_permission')) {
// 执行操作
}
}
}
}
方法二:权限指令
javascript
// 注册权限指令
Vue.directive('permission', {
inserted: function(el, binding) {
const permission = binding.value
const permissionList = this.$store.getters.getPermissionList
if (!hasPermission(permissionList, permission)) {
el.classList.add('hide-by-permission')
}
}
})
// 在模板中使用
<button v-permission="'delete_permission'">删除</button>
方法三:权限组件
javascript
// 权限组件
const Permission = {
functional: true,
render: function(createElement, context) {
const { props, scopedSlots } = context
const permissionList = context.parent.$store.getters.getPermissionList
if (hasPermission(permissionList, props.value)) {
return scopedSlots.default ? scopedSlots.default() : null
}
return null
}
}
// 注册组件
Vue.component('Permission', Permission)
// 在模板中使用
<Permission value="edit_permission">
<button>编辑</button>
</Permission>
总结
通过以上方案,我们系统性地解决了前端权限控制的各类问题:
-
权限时机与存储 - 在路由守卫中获取,存储在 Vuex 中统一管理
-
路由限制 - 通过路由守卫和
meta配置实现访问控制 -
重定向问题 - 利用动态重定向函数智能跳转
-
侧边栏显示 - 基于处理后的路由配置动态生成菜单
-
团队协作 - 提供多种易用的权限部署方式
更多推荐



所有评论(0)