vue根据用户权限配置动态路由
2019-06-05 17:01
477 查看
首先让我们了解一下前端路由:路由router全部配置在前端,根据用户权限判断可以进入哪些页面
缺点:
- vue初始化的时候需要挂载全部路由,对性能有影响
- 安全性低,用户可以在地址栏跳转到无权访问的页面(可优化)
动态路由则是根据用户信息获取权限,简单来说就是根据用户信息获取其对应的权限,生成对应的路由挂载,然后动态渲染有权限的菜单于侧边栏
实现
- 定义静态路由(登录或者公用页面)、动态路由,vue初始化时只挂载静态路由
- 用户登录后,拿到用户token,调接口拿到动态路由权限DynamicRoutes,将DynamicRoutes和定义的动态路由比较,筛选出相应的用户可访问路由表
- 执行router.addRoutes(DynamicRoutes)添加动态路由
- 使用vuex存储路由表,根据vuex中可访问的路由渲染侧边栏sidebar
// beforeEach中 if (getToken() && getToken() !== 'undefined') { // 权限判断 if (!store.state.app.menuPermissions) { /* 获取后台给的权限数组 */ return new Promise((resolve, reject) => { getPermissionList().then(response => { if (response.data.stat === 1) { const userRouter = response.data.data // 检查并生成新的路由表 const DynamicRoutes = ChecAndSetPermissionRouter(userRouter) // 默认使/重定向到第一个有效的路由 for (let i = 0, leni = DynamicRoutes.length; i < leni; i++) { if (DynamicRoutes[i].children.length > 0) { DynamicRoutes[i].path = '/' DynamicRoutes[i].redirect = DynamicRoutes[i].children[0].path break } } DynamicRoutes.push({ path: '*', redirect: '/404', hidden: true }) // 全局404 /* 生成左侧导航菜单 */ store.dispatch('SetMenuPermissions', DynamicRoutes) /* 动态添加路由 */ router.addRoutes(DynamicRoutes) // /* 完整的路由表 */ store.dispatch('SetRouterPemissions', [...constantRouterMap, ...DynamicRoutes]) next(to) } }).catch(error => { router.push('/404') // /* 生成左侧导航菜单 */ store.dispatch('SetMenuPermissions', []) next() reject(error) }) }) } if (to.path === '/login') { next({ path: '/' }) } else { next() } } else { if (whiteList.indexOf(to.path) !== -1) { next() } else { next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页 } }
这里因为后台返回的不是标准的路由,所以只能根据后台返回的权限数据中的菜单名字或者其他唯一性字段到默认定义的动态路由中筛选出有权限的路由组成路由表,这里的ChecAndSetPermissionRouter方法就是干这个的(ChecAndSetPermissionRouter方法比较多,放末尾参考)
踩坑来了
Q:为什么404 页面一定要最后加载,放置在静态路由中会怎么样?
放在静态路由里,后面的所以页面都会被拦截到404,所以应该获取动态路由权限之后push
Q:权限获取成功,不跳转新生成的动态路由,跳404?
beforeEach中router.addRoutes之后的next()可能会失效,因为可能next()的时候路由并没有完全add完成,可替换成
next(to),重新进入router.beforeEach这个钩子,这时候再通过next()来释放钩子,就能确保所有的路由都已经挂在完成了。
Q:$router.addRoutes()动态添加的路由怎么删除掉?
在开发中,有新增编辑删除菜单并要求左侧边栏菜单及时更新的需求,如果直接addRoutes,warn如下:
解决:addRoutes之前要清除掉上次addRoutes的路由,所以操作菜单调取最新权限后重新初始化router,进行matcher赋值
// DynamicRoutes是最新权限路由 const createRouter = () => new Router({ mode: 'hash', routes: [] }) const newRouter = createRouter() // resetRouter() this.$router.matcher = newRouter.matcher this.$router.addRoutes(DynamicRoutes)
Q:莫名其妙的无限循环
vue-admin-template,遇到二级菜单children为空的权
20000
限,报错如下:
解决:按照github-issues上方法,在SidebarItem.vue里改一下data就好了(没想通为啥)
// 更改后如下,return {} data() { this.onlyOneChild = null return {} }
附:ChecAndSetPermissionRouter
import { dynamicRouterMap } from '@/router' export function ChecAndSetPermissionRouter(permissionDatas) { // 获取到权限hashmap var permissionHashMap = null permissionHashMap = GetPermissionHashMap(permissionDatas) // 标记路由表 var newDynamicRouterMap = [] newDynamicRouterMap = objDeepCopy(dynamicRouterMap) newDynamicRouterMap.forEach(item => { MarkRouter(null, item, permissionHashMap) }) // 重设路由表 for (let i = 0; i < newDynamicRouterMap.length; i++) { if (ResetRouter(newDynamicRouterMap, newDynamicRouterMap[i])) { i-- // 注意:防止移除后索引错位 } } return newDynamicRouterMap } function GetPermissionHashMap(permissionDatas) { var permissionHashMap = {} permissionDatas.forEach(item => { SetKeyValueOfNodes(null, item, permissionHashMap) }) return Object.assign({}, permissionHashMap) } // 深拷贝,递归重新设置前端路由表,避免数据复用 function objDeepCopy(source) { var sourceCopy = source instanceof Array ? [] : {} for (var item in source) { sourceCopy[item] = typeof source[item] === 'object' ? objDeepCopy(source[item]) : source[item] } return sourceCopy } // 为权限hashmap的属性赋值,新增属性tempKey/tempKey2 function SetKeyValueOfNodes(p, c, permissionHashMap) { // 需要匹配的组合类型 var tempKey = (p ? p.name : 0) + '_' + c.name var tempKey2 = c.name + '_' + c.name // 赋值 permissionHashMap[tempKey] = 1 permissionHashMap[tempKey2] = 1 // 递归遍历子节点赋值 if (c.children != null && c.children.length > 0) { c.children.forEach(item => { SetKeyValueOfNodes(c, item, permissionHashMap) }) } } // 标记路由表 function MarkRouter(p, c, permissionHashMap) { var key = (p ? p.meta.title : 0) + '_' + c.meta.title // 使用拼接的key作为参考标记去匹配有权限的路由表 if (HasPermission(key, permissionHashMap)) { if (p != null) { p.keep = true // 保留当前节点 } if (c != null) { c.keep = true } } if (c.children && c.children.length > 0) { c.children.forEach(item => { MarkRouter(c, item, permissionHashMap) }) } } // 校验后端接口是否存在当前节点 function HasPermission(key, permissionHashMap) { return permissionHashMap[key] === 1 } // 重置路由表 function ResetRouter(p, c) { if (c == null) { return false } if (p.children && !c.keep) { p.children.splice(p.children.indexOf(c), 1) return true } else if (!c.keep) { p.splice(p.indexOf(c), 1) return true } if (c.children && c.children.length > 0) { for (let i = 0; i < c.children.length; i++) { if (ResetRouter(c, c.children[i])) { i-- // 注意:防止移除后索引错位 } } } return false }
相关文章推荐
- Vue-router中beforeEach钩子函数实现路由拦截,判断用户权限跳转至登录页面。
- vue前后分离动态路由和权限管理方案
- vue权限管理和使用addRoutes动态加载路由
- vue-router 根据权限跳转路由
- asp.net 2.0下根据权限动态控制菜单、动态配置导航信息 .
- asp.net 2.0下根据权限动态控制菜单、动态配置导航信息
- andorid后台根据用户权限配置前台菜单功能实现
- Vue小模块之用户登录功能(一)工程创建和路由配置
- vue-router如何根据不同的用户给不同的权限
- 根据用户权限,动态显示用户菜单
- Vue路由(vue-router)配置实战——动态路由,重定向,工程非根目录
- vue-router如何根据不同的用户给不同的权限
- Spring Boot Security 学习笔记-根据登陆人动态配置权限-密码加密验证
- vue addRoutes实现动态权限路由菜单的示例
- jira 3.13.5版 安装 配置 用户权限控制
- Visual Studio中根据系统区分引用64位、32位DLL动态库文件的配置方法
- 如何根据用户权限屏蔽或显示SAP的订单中的成本显示
- Vue的路由动态重定向和导航守卫
- vue监控路由变化 vue路由配置
- Solaris10 普通用户配置NTP出现 svcadm: svc:/network/ntp:default 权限被拒绝