中后台项目RBAC权限设计

1,839 阅读4分钟

权限设计思路

  • 在本项目中,使用了RBAC模式的权限设计,即设计不同的角色,给角色添加对应的权限页面,那么只需要记录登陆用户的角色属性,就可以给到相对应的权限
  • 操作逻辑流程:会给用户分配对应的角色,在角色中可以分配对应的权限,权限则可以通过权限管理点操作增加删除编辑的详细操作

WechatIMG596.jpeg

  1. 先给用户分配角色

WechatIMG597.jpeg

WechatIMG598.jpeg 2.再给角色分配权限

WechatIMG599.jpeg

WechatIMG600.jpeg 3. 在权限管理点可以操作权限的增删改

WechatIMG601.jpeg

WechatIMG602.jpeg

权限分配的具体实现

  • 实现方法:在给用户分配了角色,给角色分配了权限后,我们就可以对权限进行管理,在权限管理点,有标识,该标识是和项目的路由模块相对应的,如果该权限拥有对应的标识那么就可以拥有对应的路由模块,也就可以进入到对应的页面,筛选出标识对应的路由模块,使用vue-router提供的addRoutesAPI方法,动态添加路由规则

WechatIMG603.jpeg

  • 实现逻辑:在用户登陆时,获取用户资料中的对应标识,通过标识和路由模块进行对比筛选出符合权限的路由模块,然后通过addRoutes动态添加路由规则

WechatIMG604.jpeg

在vuex中实现路由模块的筛选

  • vuex代码逻辑:在state中定义初始化静态路由,在mutations中通过参数接受筛选后的动态路由规则,并且和静态路由合并,在actions中接收资料中定义的标识,然后通过和标识的对比,筛选出所拥有的动态路由权限
  • 代码
// constantRoutes是默认都拥有的静态路由 
 // asyncRoutes谁所有的动态路由模块
 // 都定义在了脚手架的路由文件中
import { constantRoutes, asyncRoutes } from '@/router' 
const state = {
  // 一开始就有静态路由的权限
  routes: constantRoutes // 路由表 表示当前用户所有的路由表
}
const mutations = {
  // 定义修改routers的mutations 
  //  newRoutes这个参数指已经筛选后的动态路由
  setRoutes(state, newRoutes) {
    state.routes = [...constantRoutes, ...newRoutes] //让静态路由和筛选后的动态路由合并
  }
}
const actions = {
  // 筛选权限路由
  // 第二个参数为当前用户拥有的菜单权限menus 就是后端穿过来的用户资料里用来做权限设计的标识
  filterRoutes(context, menus) {
    const routes = []
    // filter筛选动态路由
    menus.forEach(key => {
      // key是标识
      routes.push(...asyncRoutes.filter(item => item.name === key)) // 得到一个用户权限的路由列表
    })
    //  includes筛选
    // asyncRoutes.forEach(item => {
    //   if (menus.includes(item.name)) {
    //     routes.push(item)
    //   }
    // })

    // filter+includesd组合过滤
    // routes = asyncRoutes.filter(item => menus.includes(item.name))
    context.commit('setRoutes', routes)
    return routes // state数据是为了显示菜单 return是为了给addRoutes添加使用
  }
}
export default {
  namespaced: true,
  state,
  mutations,
  actions
}

在路由守卫中调用Vuex实现权限分配

  • 实现逻辑:由于之前在路由守卫中就通过vuex获取过用户资料,而筛选路由模块所需的标识,就在用户资料中,所以在获取用户资料的vuex中return了用户资料,在路由守卫调用时接收数据,然后再调用筛选路由权限的vuex,填入对应的标识,实现筛选,筛选后同样也使用return返回筛选后的路由规则数组,最后使用addRoutes方法,填入筛选后的路由规则数组,实现权限的分配
  • 代码实现
// 权限拦截在路由跳转  导航守卫
import router from '@/router'
import store from '@/store' // 引入store实列
import NProgress from 'nprogress' // 引入一份进度条插件
import 'nprogress/nprogress.css' // 引入进度条样式
      if (!store.getters.userId) {
       // 获取用户资料的vuex  roles是解构出的用户资料,是一个对象,标识是里面的menus属性
        const { roles } = await store.dispatch('user/getUserInfo')
        // 筛选用户的可用路由的vuex 
        const routes = await store.dispatch('permission/filterRoutes', roles.menus)
        // 404需要放到最后 因为addRoutes本质是追加动作
        router.addRoutes([...routes, { path: '*', redirect: '/404', hidden: true }])
        next(to.path) //第一次next方形时需要使用to.path再跳转一遍路由守卫,防止直接跳转但是动态路由还没有添加完的情况,如果出现这个情况那就会找不到页面,404
      } else {
        next()
      }
  • 遇到的问题:我项目中的菜单栏是使用了router.options的方法得到的所有路由规则然后渲染到页面菜单栏,由于addRoutes不能更新this.$router.options的数据,所以导致在动态路由添加后,项目侧边的菜单栏无法显示

WechatIMG605.jpeg

  • 解决办法:使用vuex的getter属性,映射到筛选后的路由模块,在菜单组件中调用渲染,就可以成功的解决菜单无法动态渲染的问题

  • 注意点:在用户登陆退出后,也需要重置路由信息并且清空当前的动态路由表,否则在下一次登入时就会携带上一次的权限