如何实现前端RBAC权限管理

·  阅读 268

在实现管理功能前,这两种路由实际上是写死的,任何用户登录进来都可以看到全部的路由,我们的需求是:不同的用户根据权限的不同看到的菜单是不同的

在路由中,我们将录由分为了两部分,动态路由和静态路由

动态路由:根据权限用户可以访问到的路由

静态路由:所有用户都可以访问的路由

在初始化路由的index.js中原路由,之后开始操作

import Vue from 'vue'
import Router from 'vue-router'

// 引入动态路由模块
import departmentsRouter from './modules/departmentsRouter.js'
import settingRouter from './modules/settingRouter.js'
import employeesRouter from './modules/employeesRouter.js'
import permissionRouter from './modules/permissionRouter.js'

Vue.use(Router)

// 动态路由
export const asyncRoutes = [
  departmentsRouter, // 部门管理
  settingRouter, // 角色管理
  employeesRouter, // 员工管理
  permissionRouter, // 权限管理
]

// 静态路由(不需要特殊的权限控制,就可以访问的页面)
export const constantRoutes =[
    //略
]

const router = createRouter()
const createRouter =  () => new Router({
  scrollBehavior: () => ({ y: 0 }),
  // 合并两个路由
  routes: [...constantRoutes, ...asyncRoutes]
})

export default router
复制代码

删除之前合并的动态路由

routes: [...constantRoutes]
复制代码

因为不同的用户登录进来看到的是根据其权限所显示的页面,所以我们要在前置路由守卫中进行操作

/ 路由前置守卫
const whiteList = ['/login', '/404']
router.beforeEach(async(to, from, next) => {
  // 限制跳转
  // 登录用户不能再次回到login,没有登录就不能访问login之外的其他页面
  const token = store.state.user.token
  NProgress.start()
  if (token) {
    if (to.path === '/login') {
      next('/')
      NProgress.done()
    } else {
      // 若没有userid则获取,有则不获取
      if (!store.state.user.userInfo.userId) {
        // 1. 获取用户个人信息
        await store.dispatch('user/getUserProfile')
        // 根据用户的权限筛选动态路由存储到vuex中
        const userMenu = store.state.user.userInfo.roles.menus
        const res = asyncRoutes.filter(item => userMenu.includes(item.children[0].name))
        // 将404加到路由的最后,否则刷新会出现404页面
        res.push({ path: '*', redirect: '/404', hidden: true })
        // 动态生成可以访问的菜单:知识让我们能访问,左侧菜单并没有显示
        router.addRoutes(res)
        store.commit('menu/setMenuList', res)
        // 解决刷新出现白屏的bug
        next({
          ...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
          replace: true // 重进一次, 不保留重复历史
        })
      } else {
        next()
      }
    }
  } else {
    // 没有token
    if (whiteList.includes(to.path)) {
      next()
    } else {
      next('/login')
    }
  }
})
复制代码

主要代码为以下:

将静态路由和动态路由存储到vuex中

// 保存左侧菜单信息
import { constantRoutes } from '@/router'
export default {
  namespaced: true,
  state: {
    // 先以静态路由作为菜单数据的初始值
    menuList: [...constantRoutes]
  },
  mutations: {
    setMenuList(state, asyncRoutes) {
      // 将动态路由和静态路由组合起来
      state.menuList = [...constantRoutes, ...asyncRoutes]
    }
  }
}
复制代码

从vuex中获取路由,使用router的api,router.addRoutes()动态添加vuex中获取到的用户访问权限路由

        // 1. 获取用户个人信息
        await store.dispatch('user/getUserProfile')
        // 根据用户的权限筛选动态路由存储到vuex中
        const userMenu = store.state.user.userInfo.roles.menus
        const res = asyncRoutes.filter(item => userMenu.includes(item.children[0].name))
        // 将404加到路由的最后,否则刷新会出现404页面
        res.push({ path: '*', redirect: '/404', hidden: true })
        // 动态生成可以访问的菜单:知识让我们能访问,左侧菜单并没有显示
        router.addRoutes(res)
        store.commit('menu/setMenuList', res)
复制代码

因为这种方法只能访问这个路由页面,菜单还未渲染,找到菜单页面将其渲染到页面即可

<template>
<sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
</template>
<script>
export default {
    computed:{
        routes(){
            return this.$store.state.menu.menuList
        }
    }
}
</script>
复制代码

之后测试不同账号就可以实现根据不用账号的权限显示不同的菜单功能

分类:
前端
标签: