前言

想必大家都知道,在 vue 中实现权限管理的核心方法是 vue-router 中的路由守卫,那么这里我们全局搜索一下 vue-router 的钩子看看有什么线索:

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/93389874-3d78-4e2f-81c8-568e684b57d7/Untitled.png

显然,在 vue-element-admin 中,实现权限管理的地方是 src/permission.js 中。

分析

可以看到,这里的宏观架构如下所示:

router.beforeEach(async (to, from, next) => {
	/* do something */
})

router.afterEach(() => {
  /* do something */
})

其中 afterEach 中做的事很简单:NProgress.done(),作用是结束顶部的 router 跳转进度条。

接下来我们看看 beforeEach 中具体的逻辑是怎么样的。

router.beforeEach(async (to, from, next) => {
  NProgress.start()
  document.title = getPageTitle(to.meta.title)
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        try {
          const { roles } = await store.dispatch('user/getInfo')

          const accessRoutes = await store.dispatch(
            'permission/generateRoutes',
            roles
          )

          router.addRoutes(accessRoutes)

          next({ ...to, replace: true })
        } catch (error) {
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

乍一眼似乎有很多的 if-else 嵌套,实际上这里的逻辑已经写的相当清晰了,仔细看一下就能分析出其中的逻辑:

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9e1bb98e-5f73-44c7-a1ee-a5128d176650/Untitled.png

这里有一些小细节值得一提:

接下来我们顺着上面的思路,深入去看看这里是如何动态生成路由的:

generateRoutes

generateRoutes({ commit }, roles) {
  return new Promise(resolve => {
    let accessedRoutes
    if (roles.includes('admin')) {
      accessedRoutes = asyncRoutes || []
    } else {
      accessedRouteszuizho  = filterAsyncRoutes(asyncRoutes, roles)
    }
    commit('SET_ROUTES', accessedRoutes)
    resolve(accessedRoutes)
  })
}de   

显然,accessedRoutes 就是最终生成的路由表。这里的逻辑也很简单,根据权限确定是否需要过滤 asyncRoutes 中的部分路由即可,而 asyncRoutes,我们可以看到,它来自 router 中:

export const asyncRoutes = [
	/* ... */
]