vue2 根据权限动态添加路由菜单

文章目录

  • 前言
  • 一、静态路由
  • 二、根据权限动态添加路由
  • 总结

前言

在我们的权限管理系统中,需要根据当前用户的角色返回对应的权限,并且根据自身的权限来限制当前用户可以看到的页面、菜单以及资源。

我们拿一个简单的案例进行讲解,假设有一个学生管理系统。这个系统有若干个角色,分别有老师和管理员,老师在这个系统下只能管理学生信息,管理员就可以管理到整个系统范围,也可以对老师进行管理,只要他有这个权限的话。这么说可能有点抽象,其实同一个系统下,不同角色看到的系统的页面可能是不一样的。

由于他们的对应的角色不一致,在左侧导航栏看到的菜单也是不一致。假设系统有3个模块,学生管理,教师管理等等之类的,那么老师这个角色在左侧菜单只能看见学生管理,因为她只有这个菜单权限。而管理员一般都是有整个系统的所以权限,所以他的菜单栏一般都是显示全部。

废话不多说开始展示案例!


一、静态路由

在我们生成动态路由前,必须先定义一些静态路由并且这些静态路由都是不需要权限就可以进行访问页面的,一般为我们的登录页面、404页面、403页面。

// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    redirect: () => ('/index'),
  },
  {
    path: '/error-404',
    name: 'error-404',
    component: () => import('@/views/Error404'),
    meta: {
      layout: 'blank',
      resource: 'Public',
    },
  },
  {
    path: '/login',
    name: 'auth-login',
    component: () => import('@/views/Login'),
    meta: {
      layout: 'blank',
      resource: 'Public',
      redirectIfLoggedIn: true,
    },
  },
  {
    path: '/not-permission',
    name: 'misc-not-authorized',
    component: () => import('@/views/NotAuthorized'),
    meta: {
      layout: 'blank',
      resource: 'Public',
    },
  },
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
  scrollBehavior() {
    return { x: 0, y: 0 }
  },
})

export default router

二、根据权限动态添加路由

动态添加路由的关键其实就是在外面vue-router中的导航守卫进行拦截,其实说白了就是在导航守卫进行拦截的时候用vuex判断当前是否加载过路由信息(因为浏览器刷新页面后,路由也就会被刷新掉),如果当前属于登录状态并且vuex的路由状态为false时,那么就重新加载一遍我们的路由信息,并且将此次的路由请求重定向。

permission.js文件的作用就是对路由进行拦截,这段代码的逻辑就是:

1.首先路由被拦截,查看当前的是否进行了登录,如果没有登录就直接跳转到登陆页面。

2.如果已经登录了,就判断是否已经加载过路由(这里是根据vuex进行判断),如果没有加载过路由就加载一遍我们的权限菜单并且动态添加到路由中;如果已经加载过路由了,那么就判断前往的路由是否拥有权限,如果有权限则放行,没有则拦截到403页面。

// router/permission.js
import router from '@/router/index'
//进行鉴权的方法,可以根据自身的需求修改
import { canNavigate } from '@/plugins/acl/routeProtection'
import store from '@/store'

// ? Router Before Each hook: https://router.vuejs.org/guide/advanced/navigation-guards.html
router.beforeEach(async (to, _, next) => {
  
  const userData = localStorage.getItem('userData')
  const isLoggedIn = userData && localStorage.getItem('userInfo') && localStorage.getItem('userAbility')

  if (isLoggedIn) {
    if (!store.state.menu.menuData) {
      await store.dispatch('menu/reloadRouter').then(() => {
        const data = JSON.parse(localStorage.getItem('menuList'))
        if (data) {
          // 避免每次加载都进入404页面
          router.addRoute({ path: '*', redirect: 'error-404'})
          // 遍历当前的权限菜单进行添加
          for (let index = 0; index < data.length; index++) {
            const element = data[index]
            if (element.parentId === -1) {
              continue
            }
            const urlArr = element.href.split('/')
            //可根据自身的需求调整
            const obj = {
              path: `${element.href}`,
              name: `${urlArr[urlArr.length - 1]}`,
              component: () => import(`@/views${element.href}`),
              meta: {
                  layout: 'content',
                  resource: `${element.code}`,
              },
            }
            router.options.routes.push(obj)
            router.addRoute(obj)
          //   next(to.path)
          next({ ...to, replace: true })
          }
        }
      })
    } else {
      if (!canNavigate(to)) {
        return next({ name: 'misc-not-authorized' })
      } 
      next()
    }
  } else {
    if (to.path !== '/login') {
      return next({ name: 'auth-login', query: { marketplace: to.query.marketplace } })
    }
    next()
  }
})
// store/modules/menu.js
import AuthApi from '@/api/auth'
import router from '@/router'

export default {
  namespaced: true,
  state: {
    menuData: false, // 存储菜单数据
  },
  mutations: {
    setMenuData(state, data) {
      state.menuData = data
    },
  },
  actions: {
    async reloadRouter({ commit }) {
      const menuListJson = localStorage.getItem('menuList')
      if (menuListJson !== '') {
        commit('setMenuData', true)
      } else {
        const userData = localStorage.getItem('userData')
        const user = JSON.parse(userData)
        const res = await AuthApi.me(user.id) // 根据用户 ID 从数据库中获取菜单数据
        const { data } = res.data
        if (data.permissionDtos.menuList) {
          localStorage.setItem('menuList', JSON.stringify(data.permissionDtos.menuList))
          commit('setMenuData', true) // 存储菜单数据到 Vuex 中
        }
      }
    },
  },
}

总结

以上就是今天要分享的内容,本文仅仅简单介绍了vue动态路由加载的使用,如果有错误或者还有更好优化的地方或不足的地方,请指出,毕竟本人并不是一名专业前端,只是业余选手。

你可能感兴趣的:(vue.js,前端,前端框架)