VUE中使用router.addRoutes进行管理菜单权限

20 篇文章 1 订阅

addRoutes

vue 动态添加路由 官方文档

需求:不同用户登陆后台,针对用户角色添加不同的权限

思路:在路由全局前置守卫中,从后台获取用户最新的权限列表,使用 addRoutes 方法,动态更新用户权限

// src/permission.js

import router from './router'

import { getToken } from '@/utils/auth' // get token from cookie

const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist

router.beforeEach(async (to, from, next) => {

  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
    } 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 {
            
          // 获取用户信息
          const userInfo = await store.dispatch('user/getInfo')
          const { role_id } = userInfo
          // 根据角色生成可访问的路由表
          const accessRoutes = await store.dispatch('permission/generateRoutes', role_id)

          // 动态添加可访问的路由
          router.addRoutes(accessRoutes)

          // hack 方法,确保addRoutes是完整的
          // replace设为true
          next({ ...to, replace: true })

        } catch (error) {
          // 删除token-提示错误-重定向到登录页面
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
        }
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next(`/login?redirect=${to.path}`)
    }
  }
})

router.afterEach(() => {
  ...
})

对路由进行二次处理,加入 Layout 组件,不同项目不同的处理方式,最终返回 vue-router 能正确解析的格式

// store/modules/permission.js

import { constantRoutes } from '@/router'
import Layout from '@/layout'

// 获取用户权限的路由接口
import { getRoutes, getQueryPermission } from '@/api/role'

const componentsMap = { // 定义好的路径
    '/': () =>
        import('@/views/dashboard'),
    '/setting/menu': () =>
        import('@/views/setting/menu'),
    '/setting/user': () =>
        import('@/views/setting/user'),
    '/setting/role': () =>
        import('@/views/setting/role'),
    // ...
}

/**
 * 递归处理后端返回路由,最后返回 vue-router 能正确解析的格式
 * @param routes 后端返回的路由表
 * @param isFilterBtn 是否过滤掉按钮
 * @param isParent 是否是最外层的节点
 * @returns {[]}
 */
function filterRouters(routes, isFilterBtn, isParent = true) {
    const res = []

    routes.forEach(route => {
        const tmp = {
            ...route
        }
        const router = generateRouter(tmp, isParent)

        // 过滤按钮类型菜单
        if (isFilterBtn) {
            if (tmp.menu_type !== 3) {
                if (router.children) {
                    router.children = filterRouters(router.children, isFilterBtn, false)
                }

                res.push(router)
            }
        } else {
            if (router.children) {
                router.children = filterRouters(router.children, isFilterBtn, false)
            }

            res.push(router)
        }
    })

    return res
}

/**
 * 替换后端返回路由表中字段
 * @param item
 * @param isParent 是否是最外层的节点
 * @returns {{path: *, component: (*), hidden: *, meta: *, name: *}}
 */
function generateRouter(item, isParent) {
    let hidden = false

    // 将后端返回的 roles 字符串类型转换为数组类型(暂时干掉了这个字段,后端只返回有权限的菜单,前端不判断)
    if (item.meta && item.meta.roles) {
        item.meta.roles = [item.meta.roles]
    }
    item.meta.noCache = item.is_cache !== 1

    if (item.is_visible === 1) {
        hidden = false
    } else {
        hidden = true
    }

    const meta = Object.assign({}, item.meta)
    delete meta.icon // 暂时删掉 icon
    const router = {
        menu_type: item.menu_type,
        menu_id: item.menu_id,
        path: item.path,
        name: item.cache_name,
        title_name: item.name,
        hidden: hidden,
        meta: meta,
        component: isParent ? Layout : componentsMap[item.path]
    }

    if (item.children && item.children.length) router.children = item.children
    return router
}

const state = {
    routes: [], // 当前角色权限的菜单
    addRoutes: [],
    allRoutes: [], // 所有的菜单
    assessedBtnRoutes: []
}

const mutations = {
    SET_ROUTES: (state, routes) => {
        state.addRoutes = routes
        state.routes = constantRoutes.concat(routes)
    },
    SET_ALL_ROUTES: (state, routes) => {
        state.allRoutes = routes
    },
    SET_ASSESSED_BTN_ROUTES: (state, routes) => {
        state.assessedBtnRoutes = routes
    }
}

const actions = {
    generateRoutes({
        commit,
        dispatch
    }, role_id) {
        return new Promise(resolve => {
            let accessedRoutes
            let allRoutes
            let accessedBtnRoutes
            // 如果是 admin 角色,拥有所有权限 asyncRoutes

            // 本地路由 asyncRoutes 过滤对应权限
            // if (roles.includes('admin')) {
            //   accessedRoutes = asyncRoutes || []
            // } else {
            //   accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
            // }
            // commit('SET_ROUTES', accessedRoutes)
            // resolve(accessedRoutes)

            // 服务端路由
            getRoutes().then(response => {
                const {
                    data
                } = response

                // 服务端未做路由权限,全部返回,filterAsyncRoutes 过滤对应权限
                // 如果是 admin 角色,拥有所有权限 asyncRoutes
                // if (roles.includes('admin')) {
                //   accessedRoutes = convertRouter(data) || []
                // } else {
                //   accessedRoutes = filterAsyncRoutes(convertRouter(data), roles)
                // }

                // TODO  add 404 router
                // 服务端做了路由权限,返回当前角色下的路由 直接用服务端返回路由,整理下格式就可以
                // let lastRoutes = filterRouters(data) || []
                // accessedRoutes = lastRoutes.push({ path: '*', redirect: '/404', hidden: true })
                getQueryPermission({
                    role_id
                }).then(response => {
                    // 只有权限的路由(无按钮)
                    accessedRoutes = filterRouters(data, response.data, true) || []

                    // console.log(accessedRoutes, '---accessedRoutes')

                    // 全部路由
                    allRoutes = filterRouters(data, false) || []

                    // 只有权限的路由(有按钮)
                    accessedBtnRoutes = filterRouters(data, response.data, false) || []
                    commit('SET_ROUTES', accessedRoutes)
                    commit('SET_ALL_ROUTES', allRoutes)
                    commit('SET_ASSESSED_BTN_ROUTES', accessedBtnRoutes)
                    resolve(accessedRoutes)
                })
            })
        })
    }
}

export default {
    namespaced: true,
    state,
    mutations,
    actions
}

main.js 文件中引入权限管理文件

import Vue from 'vue'

import App from './App'
import store from './store'
import router from './router'

import './permission' // 权限控制

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

这样,我们在每一次登录及刷新页面的时候,都会从后台获取最新的用户信息,实时权限列表更新

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端的Vue权限管理是指在Vue框架对用户角色进行权限控制,包括菜单权限和按钮权限。其菜单权限指的是用户所能看到的菜单列表,而按钮权限指的是用户在进行操作时能够操作的按钮。 在实现前端Vue权限管理时,我们可以通过调用后台接口来获取用户的权限信息。后台接口会返回一个权限列表,其包含菜单权限和按钮权限的相关信息。通过解析这个权限列表,我们可以构建出一个路由表,然后使用Vue的路由守卫功能来控制用户的访问权限。 在构建路由表时,我们可以使用Vuerouter.addRoutes方法来根据后台接口传递的数据动态生成路由。首先,我们需要将后台返回的权限列表转换成Vue路由的配置对象,然后通过调用router.addRoutes方法将这些配置对象添加到路由表。这样,当用户登录成功后,根据其权限信息动态生成的路由表就会生效。 在路由守卫,我们可以通过在每个路由的meta字段设置对应的权限信息,然后在beforeEach钩子函数进行权限判断。当用户访问一个需要权限的路由时,我们可以根据用户的角色和权限信息来判断该用户是否有权访问该路由。如果有权访问,则继续进行路由跳转;如果没有权限,则进行相应的处理,如跳转到一个没有权限的页面或者提示用户无权限等。 综上所述,前端的Vue权限管理是通过调用后台接口获取用户的权限信息,并根据这些信息动态生成路由表来控制用户的菜单权限和按钮权限。通过使用Vue的路由守卫功能,我们可以在每个路由的beforeEach钩子函数进行权限判断,从而实现前端的权限管理功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值