router.addroutes 动态添加路由表实现权限控制

2021 年 11 月 5 日 星期五(已编辑)
/
29
这篇文章上次修改于 2024 年 7 月 20 日 星期六,可能部分内容已经不适用,如有疑问可询问作者。

阅读此文章之前,你可能需要首先阅读以下的文章才能更好的理解上下文。

router.addroutes 动态添加路由表实现权限控制

开发后台管理系统会涉及到根据用户权限来动态渲染侧边栏的问题,在vue2.2.0之后可以使用router.addroutes()来方便动态添加路由了。

addRoutes (routes: RouteConfig[]): void;
//动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。

先介绍下实现侧边栏动态渲染的大致方式:

router.js中配置静态路由表:


export const constantRouterMap = [{
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },]

配置需要动态渲染的路由表:

export const asyncRouterMap = [{
    path: '/admin',
    component: () => import('@/views/admin/index'),
    hidden: true,
    meta: {
          title: 'xxx',
          icon: 'xxx',
          //角色权限字段
          role: ['admin']
        }
    },
    {
        ...
        //其他路由
    }]

用户登录跳转时,导航守卫router.beforeEach()发起ajax获取用户信息,拿到用户信息对应的role字段,再与asyncRouterMap[i].meta.role进行比对,将比对结果作为条件滤出角色所属的路由表。

//permission.js
router.beforeEach(async (to, from, next) => {
  // 验证用户是否已经登陆过
  const hasToken = getToken()
  if (hasToken) {
    if (to.path === '/login') {
    //是否跳转登录页
      next({
        path: '/'
      })
    } else {
      //这一步为了路由数据持久化,防止刷新后vuex数据丢失造成的侧边栏显示异常
      const hasGetRouters = store.getters.routers
      //是否已经获取用户信息
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo && hasGetRouters.length) {
        next()
      } else {
        try {
        //获取角色信息
          const {
            role
          } = await store.dispatch('user/getInfo')
          //传入角色信息,执行过滤方法
          await store.dispatch('permission/getRoutes', {
            role
          })
          //动态添加路由
          router.addRoutes(store.getters.addRouters);
          next({
            ...to,
            replace: true
          })
        } catch (error) {
        }
      }
    }
  }
})

遇到的一些坑

已经成功拿到动态路由表,为什么使用router.addRoutes()添加的路由没有在router.options中更新?

作者有提到That is normal, options is the object passed to the vuerouter constructor. It's not modified afterwards链接在此,其实相应的路由已经添加了,只是将参数传给了vueRouter构造函数,所以没法在vueRouter实例中看到。

那么既然侧边栏不能通过v-for="route in $router.options"渲染,如何才能实现有效更新?

如果使用router.addRoutes来进行添加路由无法更新this.$router.options,所以主要的实现方法是通过store来存储路由表。

//store
const state = {
  routers: [],
  addRouters: []
}

const mutations = {
  SET_ROUTERS: (state, routers) => {
    state.addRouters = routers;
    //与静态路由表拼接
    state.routers = constantRouterMap.concat(routers);
  }
}
const actions = {
  getRoutes({
    commit
  }, data) {
    return new Promise(resolve => {
      const {
        role
      } = data;
      
          ...
          //过滤出role对应路由表accessedRouters
      commit('SET_ROUTERS', accessedRouters);
      resolve();
    })
  }
}
//sideBar.vue

    ...mapState("permission", {
      routers: "routers",
    }),

刷新之后侧边栏显示空白?

因为vuex无法持久化保存数据,在页面刷新之后数据被清空,所以需要在router.beforeEach()内再做一层判断页面是否刷新。

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...