美文网首页Vue.jsWeb前端之路VUE常用知识点
VUE中权限+动态路由加载+配置,理论与实践!

VUE中权限+动态路由加载+配置,理论与实践!

作者: 陈宝玉啊 | 来源:发表于2019-08-26 18:22 被阅读0次

    哈喽大家好,今天我们来探讨vue开发中不可避免的动态路由权限。尤其是开发后台管理系统,其中有很多的角色需要用来做判断。不同的角色有着不同的权限。作为管理员还必须拥有修改这些权限的能力。

    这样的操作无疑会使得前端做路由的加载时显得更为复杂。我司的角色有包括管理员在内总共6种。所以我将自己在开发过程中遇到的问题整理起来。仅做参考,希望对大家有帮助!

    思路

    1.先从最高权限下手,把项目所有需要做动态分配的路由都保存到后台服务器。(可能会有人说放在后端就遏制住前端的处理了,但是根据我们目前的情况,放在后台更方便处理)。
    2.利用后台存放的数据,做成菜单树。然后给每一个想要获取权限的角色分配权限,达到每一个角色都拥有自定义权限。
    3.给创建成的不同用户分配角色,达到权限的动态分配。
    我司的处理情况特殊,也就是给不同的角色来划分权限
    4.当用户登录时,获取当前用户所在角色组,利用角色返回配置的路由信息,然后将信息加载到vue-router中,实现不同用户||角色登录进系统后,显示不同的路由菜单。

    业务代码

    1.用户登录以后,在cookie存放后台返回的Token||sessionID。
    login(userInfo).then(res => {
            if (res.code == 600) {
              resolve(res)
              return
            }
            commit('SET_TOKEN', res.res);
            setToken(res.res);
            resolve(res)
          })
    
    2.在路由守卫中,我们做判断。如果有我们要的cookie,那么就让继续加载路由。处理相关事宜,这块如有不懂。后期我会单独抽出来做一次vue路由守卫的理解。
     // 确定用户是否已登录
      const hasToken = store.getters.token;
      if (hasToken) {
        if (to.path === '/login') {
          // 如果已登录,则重定向到主页
          next({
            path: '/'
          })
          NProgress.done()
        } else {
          // 确定用户是否通过getInfo获得了他的权限角色
          const hasRoles = store.getters.roles && store.getters.roles.length > 0;
          if (hasRoles) {
            next()
          } else {
            try {
             /*
                  主要的操作在第三步
             */
            } catch (error) {
              // 删除token,进入登录页面重新登录
              await store.dispatch('user/resetToken')
              Message.error(error || 'Has Error')
              next(`/login?redirect=${to.path}`)
              NProgress.done()
            }
          }
        }
      } else {
        /* 没有token */
        if (whiteList.indexOf(to.path) !== -1) {
          // 在免费登录白名单,直接去查看
          next()
        } else {
          // 没有访问权限的其他页面被重定向到登录页面。
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    
    3.当路由守卫判断这是第一次进入系统,没有角色。所以就要开始获取角色。利用在vuex中写的异步方法请求到这一角色信息,以及对应的路由信息。
      getInfo({
        commit,
        state
      }) {
        return new Promise((resolve, reject) => {
          getInfo().then(e => {
            // 因为这里测试时只返回了路由信息,我在这里自定义了roles和name.
            var data = {
              roles: ['admin'],
              name: '长得丑活得久,长得帅老的快',
              list: e.res
            }
            const {
              roles,
              name,
            } = data;
            commit('SET_ROLES', roles)
            commit('SET_NAME', name)
            resolve(data)
          })
        })
      }
    

    获取当前角色的信息,并抛出

    ↓↓↓↓↓ 需要放入第二步空出来的区域

              // 获取路由列表
              const {
                list
              } = await store.dispatch('user/getInfo');
              //如果返回的数据列表为空,让重新登录
              if (list == undefined) {
                await store.dispatch('user/resetToken')
                next(`/${to.path}`)
                NProgress.done()
              } else {
                const accessRoutes = await store.dispatch('permission/generateRoutes', list);
                // 根据角色生成可访问路由映射
                // 动态添加可访问路由
                router.addRoutes(accessRoutes)
                // 设置replace: true,这样导航就不会留下历史记录
                next({
                  ...to,
                  replace: true
                })
              }
    

    此时抛出的data被获取到,我们拿到想要的list。通过已经定义好的递归方法,把我们传进去的list生成vue的路由,并将生成的数据返回。我们使用router.addRoutes()方法将路由加载。

    4.接第三步路由信息的处理方法。
    import {
      constantRoutes
    } from '@/router'
    
    import Layout from '@/layout'
    
    /**
     * 加载其他路由
     * @param {Object} route 
     */
    function makeOtherRouter(route) {
      var res = [];
      route.children.forEach(i => {
        const item = {
          ...i
        }
        var Unified = item.router.split('/').pop();
        var next = {
          path: Unified,
          component: () => import(`@/views${item.router}`),
          name: Unified,
          meta: {
            title: Unified
          }
        };
        // 是否可见
        if (item.visible == '0') {
          next.hidden = true;
        }
        // 子路由
        if (item.children) {
          next = {};
          next = {
            path: Unified,
            component: () => import(`@/views${item.router}/index`),
            name: Unified,
            meta: {
              title: Unified
            }
          };
          if (item.children.length == 1) {
            next.alwaysShow = true
          }
          next.children = [];
          next.children = makeRouter(item)
        }
    
        res.push(next)
      })
      return res;
    }
    
    //加载第一层路由
    export function makeFirstRouter(routes) {
      const res = [];
      routes.forEach(route => {
        const tmp = {
          ...route
        }
        var Unified = tmp.router.split('/').pop();
        if (tmp.icon) {
          var first = {
            path: tmp.router,
            component: Layout,
            name: Unified,
            meta: {
              title: Unified,
              icon: tmp.icon
            }
          }
        }
        // 第一级路由是否可见
        if (tmp.visible == '0') {
          first.hidden = true;
        }
        if (tmp.children) {
          first.children = [];
          first.children = makeOtherRouter(tmp)
        }
        if (tmp.children.length == 1) {
          first.alwaysShow = true;
        }
        res.push(first)
      })
      return res
    }
    
    const state = {
      routes: [],
      addRoutes: []
    }
    
    const mutations = {
      SET_ROUTES: (state, routes) => {
        state.addRoutes = routes
        state.routes = constantRoutes.concat(routes)
      }
    }
    
    const actions = {
      generateRoutes({
        commit
      }, list) {
        return new Promise(resolve => {
          let accessedRoutes = makeFirstRouter(list);
          //异步路由要把404放在最后加载。
          accessedRoutes.push({
            path: '*',
            redirect: '/404',
            hidden: true
          })
          commit('SET_ROUTES', accessedRoutes)
          resolve(accessedRoutes)
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    
    

    此时我们的路由就已经处理完成。大致的流程走到这里就结束了。因为数据为公司内部数据在这里就没有引用真实的数据,所以只是用语言组织的。

    后面如果找到合适的数据会再次提出来,希望对正在处理这个问题的朋友提供一点点思路和帮助。希望支持~

    未完待续!

    相关文章

      网友评论

        本文标题:VUE中权限+动态路由加载+配置,理论与实践!

        本文链接:https://www.haomeiwen.com/subject/jysdectx.html