/** * 通过meta.role判断是否与当前用户权限匹配 * @param roles * @param route */ function hasRoles (roles, route) { if (route.meta && route.meta.roles) { return roles.some(role => route.meta.roles.includes(role)) } else { return false } } /** * 递归过滤异步路由表,返回符合用户角色权限的路由表 * @param routes asyncRouterMap * @param roles */ function filterAsyncRouter(asyncRouterMap, roles) { const accessedRouters = asyncRouterMap.filter(route => { // 404 if(route.path === '*'){ return true }else if (hasRoles(roles, route)) { if (route.children && route.children.length) { route.children = filterAsyncRouter(route.children, roles) } return true } return false }) return accessedRouters } GenerateRoutes ({ commit }, data) { return new Promise(resolve => { const { roles } = data let accessedRouters if (roles.includes('admin')) { accessedRouters = asyncRouterMap } else { accessedRouters = filterAsyncRouter(asyncRouterMap, roles) } commit('SET_ROUTERS', accessedRouters) resolve() }) }
以上函数接收异步路由表、权限列表,返回在权限列表中的路由,保存在 state.addRouters 中
根据 state.addRouters 中的路由,动态生成顶部导航和侧边栏菜单
// 在有权限的路由表里,查找是否有到目标path的路由 // 为了保持路由唯一性,拼接父子路由 function hasDestRoute (froute, permitRouterMap, to) { let r = froute === '/' ? '' : froute return permitRouterMap.some(route => { let path = r + '/' + route.path if (to.path.indexOf(path) !== -1) { return true; } if (route.children && route.children.length) { //如果有孩子就遍历孩子 return hasDestRoute(path, route.children, to) } }) } /** ...省略的代码 */ SET_NOW_ROUTERS: (state, to) => { // 由于首页重定向到 /dashboard,并且不参与权限控制,特殊处理 if(to.path === '/dashboard'){ let dashboard = state.routers.filter(v => v.path === '/' ) state.sidebar_routers = dashboard[0] }else{ // 递归访问 accessedRouters,找到包含to 的那个路由对象,设置给 sidebar_routers state.addRouters.forEach(e => { if (e.children && e.children.length) { if ( hasDestRoute2(e.path, e.children, to)){ if(state.sidebar_routers.path){ // 存在 sidebar_routers 且与目标路由不同 if(state.sidebar_routers.path !== e.path){ state.sidebar_routers = e; } }else{ state.sidebar_routers = e; } } } }) } }
在路由跳转前,判断是否登录、拉取权限、生成菜单等
function hasPermission(roles, permissionRoles) { if (roles.indexOf('admin') >= 0) { return true // admin权限 直接通过 } // 没有配置权限的菜单直接进入 if (!permissionRoles){ return true } return roles.some(role => permissionRoles.indexOf(role) >= 0) } /** ...省略的代码 */ const whiteList = ['/login',] // 不重定向白名单 router.beforeEach((to, from, next) => { // 切换路由时清空上个路由未完成的所有请求 const cancelToken = axios.CancelToken clearRequest.source.cancel && clearRequest.source.cancel('CANCELD_BY_USER') clearRequest.source = cancelToken.source() // 在免登录白名单,直接进入 if(whiteList.indexOf(to.path) !== -1){ next() }else{ if(store.getters.token) { if (to.path === '/login') { next({ path: '/' }) NProgress.done() // }else{ // 判断当前用户是否已拉取完user_info信息 if(store.getters.roles.length === 0){ // 拉取用户信息 store.dispatch('GetUserInfo') .then(resp => { const roles = resp.data.roles store.dispatch('GenerateRoutes', {roles}) .then(()=>{ // 根据roles权限生成可访问的路由表 // 动态添加可访问路由表 router.addRoutes(store.getters.addRouters) next({...to, replace: true}) }) }) .catch((err) => { store.dispatch('FedLogOut').then(()=>{ Message.error({ message: err || '认证失败,请重新登录', duration: 2000, }) next({ path: '/login' }) }) }) }else{ console.log('call GenSidebarRoutes') store.dispatch('GenSidebarRoutes', to) .then(()=> { if(hasPermission(store.getters.roles, to.meta.role)){ next() }else{ next({ path: '/', query: {noGoBack: true} }) } }) } } }else{ // 重定向到登录页 next({ path: '/login', query: {redirect: to.fullpath} }) } } })
原文转载于https://www.cnblogs.com/wbjxxzx/p/10081491.html