笔者近期的项目开发都在使用Vue框架,在此整理下怎么样在Vue框架下实现ant-design-pro中菜单路由的配置方案。
背景:
一般中后台系统都需要根据当前登录用户的信息展示相应的模块,这就要求前端需要在拿到用户信息后对整个系统的菜单和路由做相应的鉴权处理。
现状:
之前接触过的菜单路由鉴权方案有以下两种:后端维护系统完整的菜单结构,用户登录后返回给前端鉴权后的菜单结构,前端只负责渲染。但是要修改icon,path的配置需要后端做处理。
2. 前端维护全量的菜单结构,在侧边栏组件中全量渲染,对于没有权限的菜单模块,点击重定向到一个403未授权页。
解决方案:
一般情况下,菜单会对应一个路由,但是某些路由没有相应的菜单展示,最典型的就是列表页和详情页(用户点击列表菜单进入列表页路由,在列表页中通过按钮触发进入详情页路由)。所以说对于鉴权需求要完成两个点:针对路由: 不管通过什么方式进入未授权的路由,进行重定向处理。
针对菜单: 不展示没有权限的菜单模块。
Vue中路由的鉴权处理:
在Vue框架中,路由的鉴权处理相对容易一些,vue-router本身提供全局的路由守卫,可以在用户进入每一个路由之前做鉴权操作:用户信息返回的权限列表和当前要进入的路由配置对象中设置的权限码做比较,不符合重定向,符合放行。
// 用户信息接口// 当前用户拥有demo页,analysis页和search页的权限。Mock.mock('/user/current', 'get', () => {
return {
name: 'Jack Ma',
authMenuKeys: ['demo', 'analysis', 'search']
}
})
// 路由配置(后面会具体介绍路由的配置方法)[
{
path: '/dashboard/analysis',
component: () => import('../views/dashboard/analysis.vue'),
meta: {
key: 'analysis'
}
}
...
]
// 全局路由钩子函数router.beforeEach(async (to, from, next) => {
// ... const isLoginSuccess = await store.dispatch('initUserInfo') // 登录操作 // 拿到登录成功后保存在vuex中的用户权限码,也就是用户信息接口中的authMenuKeys字段 const authMenuKeys = store.state.app.authMenuKeys
const toRouteKey = to.meta.key
if (isLoginSuccess && toRouteKey && authMenuKeys.indexOf(toRouteKey) === -1) { // 定位到无权限页 next({name: '403'})
} else { // 放行 next()
}
})
菜单的鉴权处理:
用户信息接口中权限列表:
authMenuKeys:['key1',‘key2’,'key3']菜单树鉴权操作示意图
系统菜单树配置可以抽象成一种森林的数据结构,我们再来考虑一种复杂的配置情况:抽象出的菜单数据结构
鉴权之后的菜单结构
核心代码:
/**
* 根据菜单权限码生成最终的树形菜单结构
* @param {Array} menu 用户定义的全量菜单树状结构
* @param {Array} authMenuKeys 用户信息中拿到的菜单权限码
* @return {Array} 鉴权后的树形菜单
*/
function getAuthMenuData(menu, authMenuKeys) { // eslint-disable-line
return menu.filter((item) => {
if (item.children && item.children.length > 0) {
item.children =