preface

Vue router router router router Router Router Router Router Router Router

Picture 1

Obviously, in vue-element-admin, the place to implement permission management is in SRC /permission.js.

Analysis of the

As you can see, the macro architecture is as follows:

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

 /* do something */

})



router.afterEach((a)= > {

  /* do something */

})

Copy the code

What afterEach does is simple: nprogress.done (), which ends the router progress bar at the top.

Let’s look at what the specific logic looks like in 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,replacetrue })

        } 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()

    }

  }

})

Copy the code

At first glance there seems to be a lot of if-else nesting, but in fact the logic here is quite clear. If you look closely, you can analyze the logic:

Picture 2

Here are a few small details worth mentioning:

  • End NProgress manually after redirecting next, see this issue for a specific reason
  • next({ ... to, replace: true })In the settingreplace: trueClears navigation records

Let’s take a closer look at how routes are dynamically generated:

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   

Copy the code

Obviously, accessedRoutes is the resulting routing table. The logic here is also very simple, according to the permission to determine whether to filter part of the asyncRoutes route, and asyncRoutes, we can see that it comes from the router:

export const asyncRoutes = [

 / *... * /

]

Copy the code

The routing table is a defined routing table. Based on the above logic, the user with the admin permission can access all routes. Otherwise, some routes are filtered out based on the corresponding permission.

So let’s look at the filtering logic:

export function filterAsyncRoutes(routes, roles{

  const res = []



  routes.forEach(route= > {

    consttmp = { ... route }

    if (hasPermission(roles, tmp)) {

      if (tmp.children) {

        tmp.children = filterAsyncRoutes(tmp.children, roles)

      }

      res.push(tmp)

    }

  })



  return res

}

Copy the code

Obviously, the entire routing table is recursively traversed, and if it has permission, it is saved to the routing table, otherwise it is filtered out.

Finally, return to SRC/Permission. js, and then obtain the dynamically generated routing table, and add it to the route through router.addroutes (), thus completing the whole dynamic route generation process.

Finally, add the brain map:

Picture 3