1. RBAC权限设计思想
-
管理员给用户分配角色
-
再给角色分配权限点, 管理员退出登录
-
角色登录显示自己能使用的权限
2. 权限应用 - 控制动态路由(导航菜单)
-
拿到当前用户可访问的所有菜单标识
-
拿到本地所有的动态路由列表
-
俩份数据配合做过滤处理得到当前用户所有可以访问的动态路由表
-
将路由表添加到路由系统中,让路由可被访问
-
将路由表添加到导航菜单里显示到左侧
开始写代码了:
1. 找到当前用户个人信息接口,把个人信息return出来
个人信息返回基本大致是这样
代码如下:
// 我这是在vuex中写的,看自己当时在什么地方写
async getUserInfo(ctx) {
// 调用获取用户信息的接口
const res = await getUserInfo()
// 获取用户头像
const info = await getUserDetailById(res.userId)
ctx.commit('setUserInfo', { ...res, ...info })
// 将个人权限数据返回
return res.roles
}
2. 引入所有的动态路由表做过滤
在路由守卫中写:
注意:router.addRoutes()方法,把动态路由添加到应用的路由系统里
import { asyncRoutes } from '@/router'
if (!store.getters.userId) {
// 拿到菜单权限数据
const roles = await store.dispatch('user/getUserInfo')
// 做过滤处理
// 如果路由的name属性能在menus权限数据中找到代表可以访问
let filterRoutes = []
// 筛选filter
filterRoutes = asyncRoutes.filter(route => {
// includes过滤
return roles.menus.includes(item.children[0].name)
})
console.log('根据权限过滤后的路由表为:',filterRoutes)
// 把动态路由添加到应用的路由系统里
// router.addRoutes(filterRoutes)
// 这样设置是不行的因为404页面跑到中间了,得把404拿过来
router.addRoutes([...filterRoutes, { path: '*', redirect: '/404', hidden: true }])
// 关键代码在这里哦
next({
...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
replace: true // 覆盖上一次的记录
})
return
}
操作一下: 手动在浏览器中输入某一个动态路由的地址,看看可不可以渲染出来对应的页面~
3. 重写菜单的生成逻辑
当前的菜单渲染使用的数据:
this.$router.options.routes
这个数据是死的,并不会随着你调用addRoutes方法而变多
这个数据并不是响应式的数据,即使里面有了数据也不会反应到视图中
也就是说,如果我们想在调用addRoutes方法之后,想要路由数据立刻反应到菜单中,我们需要像一个额外的方法,思考一下,vue开发中,哪个技术可以保证响应式特性还可以动态修改? vuex管理
1. 定义vuex管理菜单数据 menu.js
// 导入静态路由
import { constantRoutes } from '@/router'
export default {
namespaced: true,
state: {
// 先以静态路由表作为菜单数据的初始值
menuList: [...constantRoutes]
},
mutations: {
setMenuList(state, asyncRoutes) {
// 将动态路由和静态路由组合起来
state.menuList = [...constantRoutes, ...asyncRoutes]
}
}
}
又回到路由守卫js页面,调用一下setMenuList函数
if (!store.getters.userId) {
await store.dispatch('user/getUserInfo')
// 把动态路由添加到应用的路由系统里
router.addRoutes(asyncRoutes)
// 把动态路由数据交给菜单
store.commit('menu/setMenuList', asyncRoutes)
}
菜单生成部分改写使用vuex中的数据
routes() {
// 拿到的是一个完整的包含了静态路由和动态路由的数据结构
// return this.$router.options.routes
return this.$store.state.menu.menuList
}