• 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}
                })
            }
        }
    })
    
  • 相关阅读:
    pyCharm django 中新加app
    Amazon Redshift 架构
    Amazon DynamoDB 概述
    Amazon EFS 性能
    Amazon RDS 现在支持 Storage Auto Scaling
    只读副本与多可用区部署
    RDS也和EC2一样支持snapshot的跨Region复制:Cross-Region Snapshot Copy for Amazon RDS
    Automated Cross-Region Snapshot Copy for Amazon Redshift
    EC2的跨Region复制或部署,Cross Region EC2 AMI Copy
    RDS for MySQL, PostgreSQL, Aurora 都支持Cross-Region Read Replicas。采用异步复制,只读副本有网络时延
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/10081491.html
Copyright © 2020-2023  润新知