• vue-element-template 获取后端路由表动态生成权限


    主要思路如下:

    • 用户登录login获取token
    • 拿着token请求用户信息,同时后端返回一个路由表
    • 前端解析后动态添加路由表,同时存储到本地localstorage
    • 刷新页面或者退出登录或者登录过期等时,会进行相应的判断,重新渲染路由

    1、在src/utils文件夹下新建_import.js,用于匹配组件,代码如下:

    export default function (component) {
      switch (component) {
        case 'Layout':
          return require("@/layout").default
        case 'Test':
          return require('@/views/table/index').default
        default:
          return require('@/views/' + component + '/index').default
      }
    }

     2、在src/utils文件夹下新建router.js,用于解析后端返回的路由,具体解析方法和数据形式还是要看项目具体来分析,代码如下:

    import _import from "@/utils/_import"
    export default function (routers) {
      return filterAsyncRouter(routers)
    }
    //将后台返回的json权限数据格式化(递归遍历子节点)
    export const filterAsyncRouter = (asyncRouterMap) => { //遍历后台传来的路由字符串,转换为组件对象
      const accessedRouters = asyncRouterMap.filter(e => {
        if (e.component) {
          e.component = _import(e.component)
        }
        if (e.children && e.children.length) {
          e.children = filterAsyncRouter(e.children)
        }
        else
        {
          delete e.children;
        }
        if (e.redirect === '') {
              delete e.redirect
        }
        if (e.name === '') {
          delete e.name
        }
    
        if (e.meta.icon !== '' && e.meta.title !== '') { // 配置 菜单标题 与 图标
          e.meta = {
            title: e.meta.title,
            icon: e.meta.icon
          }
        } else if (e.meta.icon === '' && e.meta.title !== '') {
          e.meta = {
            title: e.meta.title
          }
        }
    
        return true
      })
      return accessedRouters
    }

    3,在src/store/modules/user.js下添加menus,用于保存后端返回的路由,代码如下:

    import { login, logout, getInfo } from '@/api/user'
    import { getToken, setToken, removeToken } from '@/utils/auth'
    import { resetRouter } from '@/router'
    import Layout from '@/layout'
    import routerFormat from '@/utils/router'
    
    const getDefaultState = () => {
      return {
        token: getToken(),
        name: '',
        avatar: '',
        roles: [],
        menus: "",   //新增
      }
    }
    
    const state = getDefaultState()
    
    const mutations = {
      RESET_STATE: (state) => {
        Object.assign(state, getDefaultState())
      },
      SET_TOKEN: (state, token) => {
        state.token = token
      },
      SET_NAME: (state, name) => {
        state.name = name
      },
      SET_AVATAR: (state, avatar) => {
        state.avatar = avatar
      },
      SET_ROLES: (state, roles) => {
        state.roles = roles
      },
      SET_MENUS: (state, menus) => {    //赋值menus
          state.menus = menus
       }
    }
    
    const actions = {
      // user login
      login({ commit }, userInfo) {
        const { username, password } = userInfo
        return new Promise((resolve, reject) => {
          login({ username: username.trim(), password: password }).then(response => {
            const { data } = response
            commit('SET_TOKEN', data.AccessToken)
            setToken(data.AccessToken)
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },
    
      // get user info
      getInfo({ commit, state }) {
        return new Promise((resolve, reject) => {
          getInfo(state.token).then(response => {
            const { data } = response
            if (!data) {
              reject('Verification failed, please Login again.')
            }
    
            const { roles, name, avatar,menus   } = data
    
            const routes = routerFormat(menus);                           //格式化后端返回的菜单
            routes.push({ path: '*', redirect: '/404', hidden: true });   //插入404页面
    
            // roles must be a non-empty array
            if (!roles || roles.length <= 0) {
              reject('getInfo: roles must be a non-null array!')
            }
    
            commit('SET_ROLES', roles)
            commit('SET_NAME', name)
            commit('SET_AVATAR', avatar)
            commit("SET_MENUS", routes) // 触发vuex SET_MENUS 保存路由表到vuex
            resolve(data)
          }).catch(error => {
            reject(error)
          })
        })
      },
    
      // user logout
      logout({ commit, state }) {
        return new Promise((resolve, reject) => {
          logout(state.token).then(() => {
            removeToken() // must remove  token  first
            resetRouter()
            commit('RESET_STATE')
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },
    
      // remove token
      resetToken({ commit }) {
        return new Promise(resolve => {
          removeToken() // must remove  token  first
          commit('RESET_STATE')
          resolve()
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }

    4,修改src/store/modules/permission.js,直接显示后端的路由,不过滤

    const actions = {
      generateRoutes({ commit }, accessedRoutes) {
        return new Promise(resolve => { 
          commit('SET_ROUTES', accessedRoutes)
          resolve(accessedRoutes)
        })
      }
    }

    5,修改src/permission.js,

    import router 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'
    const _import = require('./router/_import_' + process.env.NODE_ENV)
    
    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 {
          // determine whether the user has obtained his permission roles through getInfo
          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', store.getters.menus)
               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()
    })
  • 相关阅读:
    深入了解Element Form表单动态验证问题 转载
    使用 Element UI Select 组件的 value-key 属性,让绑定值可以为一个对象
    vue 中 使用 element-ui 发送请求前 校验全部表单,报警告: [Element Warn][Form]model is required for validate to work!
    vue element InfiniteScroll 无限滚动 入坑记录
    nginx实现跨域访问并支持(GET, POST,PUT,DELETE, OPTIONS)
    正则表达式记录
    element ui图片上传方法
    laravel 跨域解决方案
    vagrant的box哪里下?镜像在哪儿找?教你在vagrant官网下载各种最新.box资源
    Saas系统架构的思考,多租户Saas架构设计分析
  • 原文地址:https://www.cnblogs.com/xz4062006/p/14355173.html
Copyright © 2020-2023  润新知