• 【Vue】VUE模板vue-admin-template-4.4.0添加角色权限路由


    在网上看了很多教程,写的很乱,代码也没有给全。通过对比多篇博客,最终整理出了这篇文章,详细介绍了修改的过程。


    一、概述

    vue模板:vue-admin-template-4.4.0

    1.1 效果展示

    根据当前登录用户的角色信息生成对应的菜单栏。

    比如,student可以查看到的菜单栏:

    在这里插入图片描述

    admin可以查看的菜单栏:

    在这里插入图片描述

    1.2 原理简单说明(选读)

    可以最后读这部分内容加深对角色权限路由的理解

    📌 项目中的路由均写在src\router\index.js中,其中默认包含constantRoutes ,这就是我们需要解析的固定路由,无论用户的角色是什么,都需要显示这些路由内容

    export const constantRoutes = [
    	...
    ]
    
    • 1
    • 2
    • 3

    为了根据权限动态的生成路由,我们需要添加asyncRoutes ,这里面的内容将根据用户角色权限会动态生成

    export const asyncRoutes = [
    	...
    ]
    
    • 1
    • 2
    • 3

    📌 在src\store\modules\permission.js中,通过分析asyncRoutes 里面的角色权限和当前用户所拥有的角色权限,生成用户可查看到的路由列表permission_routes

    📌 在src\layout\components\Sidebar\index.vue中,遍历permission_routes显示菜单栏。

    二、后端响应(选读)

    前端的每一个请求的操作之前都会获取的用户信息,获取用户的用户名(name)、头像(avatar)和角色(roles)。

    项目默认只需要name和avatar,现在我们添加了角色roles。

    此时获取用户的响应是这样的。

    {
    	"msg":"成功",
    	"code":20000,
    	"roles":["admin"],
    	"name":"admin",
    	"avatar":"http://www.weixintouxiang.cn/weixin/20140607090832328.gif"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、配置(正文)

    要修改以下7个文件:

    文件名修改方式作用
    src\router\index.js修改路由设置
    src\store\modules\user.js修改获取角色信息
    src\store\modules\permission.js增加根据角色解析路由
    src\store\getters.js修改VUEX的Getters
    src\store\index.js修改设置所需的VUEX模块
    src\permission.js修改权限逻辑修改
    src\layout\components\Sidebar\index.vue修改侧边栏解析修改

    3.1 src\router\index.js

    固定路由的写法,不需要任何权限,所有角色都可以访问。

    /**
     * 不需要任何权限,所有角色都可以访问
     */
    export const constantRoutes = [
      {
        path: '/login',
        component: () => import('@/views/login/index'),
        hidden: true
      },
      {
        path: '/',
        component: Layout,
        redirect: '/index',
        hidden: true,
        children: [{
          path: 'index',
          component: () => import('@/views/index/index')
        }]
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    需要我们添加的地方,根据权限显示的路由

    export const asyncRoutes = [
      {
        path: '/webManage',
        component: Layout,
        meta: { roles: ['admin'] },
        children: [
          {
            path: 'index',
            name: '网站管理',
            component: () => import('@/views/webManage/index'),
            meta: { title: '网站管理', icon: 'cog-fill' }
          }
        ]
      },
      // 404 页面必须放置在最后一个页面
      { path: '*', redirect: '/404', hidden: true }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    通过修改meta属性中roles

    只有admin角色可以查看:

    meta: { roles: ['admin'] }
    
    • 1

    admin和manager都可以查看

    meta: { roles: ['admin', 'manager] }
    
    • 1

    注意:{ path: '*', redirect: '/404', hidden: true }必须放在最后面,并且只能放在asyncRoutes 中,如果放在constantRoutes 中的话,刷新页面会报404。

    3.3 src\store\modules\user.js

    修改以下部分:

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2.4 src\store\modules\permission.js

    添加该文件:

    import { asyncRoutes, constantRoutes } from '@/router'
    
    /**
     * Use meta.role to determine if the current user has permission
     * @param roles
     * @param route
     */
    function hasPermission(roles, route) {
      if (route.meta && route.meta.roles) {
        return roles.some(role => route.meta.roles.includes(role))
      } else {
        return true
      }
    }
    
    /**
     * Filter asynchronous routing tables by recursion
     * @param routes asyncRoutes
     * @param roles
     */
    export function filterAsyncRoutes(routes, roles) {
      const res = []
      routes.forEach(route => {
        const tmp = { ...route }
        if (hasPermission(roles, tmp)) {
          if (tmp.children) {
            tmp.children = filterAsyncRoutes(tmp.children, roles)
          }
          res.push(tmp)
        }
      })
    
      return res
    }
    
    const state = {
      routes: [],
      addRoutes: []
    }
    
    const mutations = {
      SET_ROUTES: (state, routes) => {
        // 这个地方维护了两个状态一个是addRouters,一个是routes
        state.addRoutes = routes
        state.routes = constantRoutes.concat(routes)
      }
    }
    
    const actions = {
      generateRoutes({ commit }, roles) {
        return new Promise(resolve => {
          const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
          commit('SET_ROUTES', accessedRoutes)
          resolve(accessedRoutes)
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    2.5 src\store\getters.js

    修改以下部分:

    在这里插入图片描述

    2.6 src\permission.js

    替换以下文件:

    import router, { constantRoutes } from './router'
    import store from './store'
    import { Message } from 'element-ui'
    import NProgress from 'nprogress' // progress bar
    import 'nprogress/nprogress.css' // progress bar style
    import { getToken } from '@/utils/auth' // get token from cookie
    import getPageTitle from '@/utils/get-page-title'
    
    NProgress.configure({ showSpinner: false }) // NProgress Configuration
    
    const whiteList = ['/login'] // no redirect whitelist
    
    router.beforeEach(async(to, from, next) => {
      // start progress bar
      NProgress.start()
    
      // set page title
      document.title = getPageTitle(to.meta.title)
    
      // determine whether the user has logged in
      const hasToken = getToken()
    
      if (hasToken) {
        if (to.path === '/login') {
          // if is logged in, redirect to the home page
          next({ path: '/' })
          NProgress.done()
        } else {
          const hasRoles = store.getters.roles && store.getters.roles.length > 0
          if (hasRoles) {
            next()
          } else {
            try {
              // get user info
              // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
              const { roles } = await store.dispatch('user/getInfo')
              // generate accessible routes map based on roles
              const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
              // dynamically add accessible routes
              router.options.routes = constantRoutes.concat(accessRoutes)
              router.addRoutes(accessRoutes)
    
              // hack method to ensure that addRoutes is complete
              // set the replace: true, so the navigation will not leave a history record
              next({ ...to, replace: true })
            } catch (error) {
              // remove token and go to login page to re-login
              await store.dispatch('user/resetToken')
              Message.error(error || 'Has Error')
              next(`/login?redirect=${to.path}`)
              NProgress.done()
            }
          }
        }
      } else {
        /* has no token*/
    
        if (whiteList.indexOf(to.path) !== -1) {
          // in the free login whitelist, go directly
          next()
        } else {
          // other pages that do not have permission to access are redirected to the login page.
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    })
    
    router.afterEach(() => {
      // finish progress bar
      NProgress.done()
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    2.7 src\layout\components\Sidebar\index.vue

    修改以下内容:

    <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
    
    • 1

    在这里插入图片描述

  • 相关阅读:
    flutter系列之:flutter中常用的container layout详解
    Flink word count入门
    java毕业设计嘉和小区智能物业(附源码、数据库)
    抖音矩阵系统。抖音矩阵系统。抖音矩阵系统。抖音矩阵系统。
    MCE | 肿瘤微环境在癌症中的作用
    TP5.1 导出excel文件
    Linux--网络概念
    std::copy代替memcpy
    Backblaze2022中期SSD故障质量报告解读
    gRPC简介
  • 原文地址:https://blog.csdn.net/See_Star/article/details/125482707