zoukankan      html  css  js  c++  java
  • vue+elementui搭建后台管理界面(6登录和菜单权限控制[二])

    根据权限计算路由的代码

    /**
     * 通过meta.role判断是否与当前用户权限匹配
     * @param roles
     * @param route
     */
    function hasRoles (roles, route) {
      if (route.meta && route.meta.roles) {
        return roles.some(role => route.meta.roles.includes(role))
      } else {
        return false
      }
    }
    
    /**
     * 递归过滤异步路由表,返回符合用户角色权限的路由表
     * @param routes asyncRouterMap
     * @param roles
     */
    function filterAsyncRouter(asyncRouterMap, roles) {
      const accessedRouters = asyncRouterMap.filter(route => {
        // 404
        if(route.path === '*'){
          return true
        }else if (hasRoles(roles, route)) {
          if (route.children && route.children.length) {
            route.children = filterAsyncRouter(route.children, roles)
          }
          return true
        }
        return false
      })
      return accessedRouters
    }
    GenerateRoutes ({ commit }, data) {
        return new Promise(resolve => {
        const { roles } = data
        let accessedRouters
        if (roles.includes('admin')) {
            accessedRouters = asyncRouterMap
        } else {
            accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
        }
        commit('SET_ROUTERS', accessedRouters)
        resolve()
        })
    },
    

    以上函数接收异步路由表、权限列表,返回在权限列表中的路由,保存在 state.addRouters 中

    动态显示顶部导航和侧边栏

    根据 state.addRouters 中的路由,动态生成顶部导航和侧边栏菜单

    // 在有权限的路由表里,查找是否有到目标path的路由
    // 为了保持路由唯一性,拼接父子路由
    function hasDestRoute (froute, permitRouterMap, to) {
      let r = froute === '/' ? '' : froute
      return permitRouterMap.some(route => {
        let path = r + '/' + route.path
        if (to.path.indexOf(path) !== -1) {
          return true;
        }
        if (route.children && route.children.length) { //如果有孩子就遍历孩子
          return hasDestRoute(path, route.children, to)
        }
      })
    }
    /** ...省略的代码 */
    SET_NOW_ROUTERS: (state, to) => {
        // 由于首页重定向到 /dashboard,并且不参与权限控制,特殊处理
        if(to.path === '/dashboard'){
        let dashboard = state.routers.filter(v => v.path === '/' )
        state.sidebar_routers = dashboard[0]
        }else{
            // 递归访问 accessedRouters,找到包含to 的那个路由对象,设置给 sidebar_routers
            state.addRouters.forEach(e => {
            if (e.children && e.children.length) {
                if ( hasDestRoute2(e.path, e.children, to)){
                    if(state.sidebar_routers.path){
                        // 存在 sidebar_routers 且与目标路由不同
                        if(state.sidebar_routers.path !== e.path){
                            state.sidebar_routers = e;
                        }
                    }else{
                        state.sidebar_routers = e;
                    }
                }
            }
            })
        }
    }
    

    关键的控制代码

    在路由跳转前,判断是否登录、拉取权限、生成菜单等

    function hasPermission(roles, permissionRoles) {
        if (roles.indexOf('admin') >= 0) {
            return true // admin权限 直接通过
        }
        // 没有配置权限的菜单直接进入
        if (!permissionRoles){
            return true
        } 
        return roles.some(role => permissionRoles.indexOf(role) >= 0)
      }
    /** ...省略的代码 */
    const whiteList = ['/login',]    // 不重定向白名单
    router.beforeEach((to, from, next) => {
        // 切换路由时清空上个路由未完成的所有请求
        const cancelToken = axios.CancelToken
        clearRequest.source.cancel && clearRequest.source.cancel('CANCELD_BY_USER')
        clearRequest.source = cancelToken.source()
    
        // 在免登录白名单,直接进入
        if(whiteList.indexOf(to.path) !== -1){
            next()
        }else{
            if(store.getters.token) {
                if (to.path === '/login') {
                    next({ path: '/' })
                    NProgress.done()  //
                }else{
                    // 判断当前用户是否已拉取完user_info信息
                    if(store.getters.roles.length === 0){
                        // 拉取用户信息
                        store.dispatch('GetUserInfo')
                        .then(resp => {
                            const roles = resp.data.roles
                            store.dispatch('GenerateRoutes', {roles})
                            .then(()=>{
                                // 根据roles权限生成可访问的路由表
                                // 动态添加可访问路由表
                                router.addRoutes(store.getters.addRouters)
                                next({...to, replace: true})
                            })
                        })
                        .catch((err) => {
                            store.dispatch('FedLogOut').then(()=>{
                                Message.error({
                                    message: err || '认证失败,请重新登录',
                                    duration: 2000,
                                })
                                next({ path: '/login' })
                            })
                        })
                    }else{
                        console.log('call GenSidebarRoutes')
                        store.dispatch('GenSidebarRoutes', to)
                        .then(()=> {
                            if(hasPermission(store.getters.roles, to.meta.role)){
                                next()
                            }else{
                                next({
                                    path: '/', 
                                    query: {noGoBack: true}
                                })
                            }
                        })
                    }
                }
            }else{
                // 重定向到登录页
                next({
                    path: '/login',
                    query: {redirect: to.fullpath}
                })
            }
        }
    })
    
  • 相关阅读:
    487-3279(电话号码)
    【模板】二分图匹配
    【模板】网络最大流
    P3879 [TJOI2010]阅读理解
    10.10 考试T1 低仿机器人
    P4025 [PA2014]Bohater
    线段树合并 从入门到入土
    CF547B Mike and Feet
    10.6洛谷月赛划水记
    P4552 [Poetize6] IncDec Sequence
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/10081491.html
Copyright © 2011-2022 走看看