在一些大型公司中,很多都有人资的中、后台系统,但在这个系统里面,不是每个人进入都可以对里面的数据进行操作。正常情况下只有少部分的人可以完成例如:人事调整,部门调整,职位调整,薪资调整等一系列的操作。
为了达成不同的帐号登陆系统后能看到不同的页面,能执行不同的功能的目标,我们有很多种解决方案,RBAC
(Role-Based Access control)权限模型 ,也就是基于角色的权限分配解决方案。
一、RBAC权限模型的组成
1. 用户(使用系统的员工账号)
一个系统首先会有用户.后台系统的用户基本都是公司的员工
2. 角色(也可以理解成职务)
角色是一个虚拟的人物,正常情况下,我们不可能对每一个用户一 一进行添加权限的操作
就算公司人员比较少,我们添加了了,后期进行人事调动的时候,重新进行权限的分配也是很麻烦的操作
3. 权限点(这个系统中有多少个功能)
每一个功能可以代表一个权限点,也可以理解成一个页面
例始:有3个页面,每个页面上各自有3,2,4个不同的操作
上面的3个页面可以理解成三个大的权限页面,权限页面里面有不同的权限操作
4.权限模型
通过对不用的用户分配拥有不同权限点的操作,实现权限的管理
注意点:
1.系统中的权限点不可以随意,必须是程序员已经开发出来的功能!!
2.角色的权限点是可以进行改变的,根据实际情况可以由系统管理员进行权限点的添加和删除
3.用户和角色是1对多的关系:一个用户可以拥有多个角色,这样他就会具体这多个角色的权限了。比如公司的董事长可以拥有财务主管和保安队长的角色: 董事长可以看财务报表,也可以查看监控。
二、RBAC权限动态生成左侧菜单-整体分析
1. 动态添加路由配置
用户能访问到的页面(路由配置)必须是动态的, 所以要先掌握一个可以动态添加路由地址的APIaddRoutes()
方法:动态添加路由配置
router.addRoutes([路由配置对象])
或者:
this.$router.addRoutes([路由配置对象])
2. 登录成功(页面跳转),进入导航守卫:
通过事先的约定值,给需要权限的页面进行name的绑定,再通过这个值进行路由的筛选和动态添加,方便后面进入主页的动态菜单生成
在路由导航文件中可以这么进行书写
// 引入所有的动态路由表(未经过筛选)
import router, { asyncRoutes } from '@/router'
const whiteList = ['/login', '/404']
router.beforeEach(async(to, from, next) => {
....
if (token) {
// 有token
if (to.path === '/login') {
next('/')
} else {
if (!store.getters.userId) {
await store.dispatch('user/getUserInfo')
// 改写成动态添加的方式
router.addRoutes(asyncRoutes)
}
next()
}
} else {
// 没有token
if (whiteList.includes(to.path)) {
next()
} else {
next('/login')
}
}
})
在路由跳转到主页前,将动态的路由添加,然后等待渲染,这样就可以完成不同角色的员工进入主页的不同菜单
这个过程我们可以使用vuex进行管理,在vuex中进行动态路由与静态路由的结合
// 导入静态路由
import { constantRoutes } from '@/router'
export default {
namespaced: true,
state: {
// 先以静态路由作为菜单数据的初始值
menuList: [...constantRoutes]
},
mutations: {
setMenuList(state, asyncRoutes) {
// 将动态路由和静态路由组合起来
state.menuList = [...constantRoutes, ...asyncRoutes]
}
}
}
三、刷新页面时的bug修复
(1).解决刷新页面后直接进入404的问题
1. 问题
(1)如果我们刷新浏览器,会发现跳到了404页面
(2)对于addRoute添加的路由,在刷新时会白屏
2. 原因
刷新浏览器,会发现跳到了404页面
现在我们的路由设置中的404页处在中间位置而不是所有路由的末尾了。
3.解决
把404页改到路由配置的最末尾就可以了,将其push进去
(2).解决刷新出现的白屏bug
在路由next()前加添加这么一段代码就可以了
if (!store.getters.userId) {
// 省略其他...
// 解决刷新出现的白屏bug
next({
...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
replace: true // 重进一次, 不保留重复历史
})
} else {
next()
}
(3).退出登录时重置路由
1.问题
退出后,再次登陆,发现菜单异常 (控制台有输出说路由重复);
2.原因
路由设置是通过router.addRoutes(filterRoutes)来添加的,退出时,并没有清空,再次登陆,又加了一次,所以有重复。
需要将路由权限重置 (恢复默认) 将来登录后再次追加才可以,不然的话,就会重复添加
3.解决
// 重置路由
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // 重新设置路由的可匹配路径
}
这个方法就是将路由重新实例化,相当于换了一个新的路由,之前加的路由就不存在了,需要在登出的时候, 调用一下即可。