权限路由设计

922 阅读3分钟
  1. 前端手动配置静态路由constantRouterMap与动态路由池asyncRouterMap,并给动态路由池配置所需权限
// 静态路由
export const constantRouterMap = [
  { path: '/login', component: () => import('@/views/login/index'), hidden: true },
  {
    path: '/',
    component: Layout,
    name: 'system',
    hidden: true,
    meta: { title: '首页' },
    children: [{
      path: '',
      name: 'Home',
      component: () => import('@/views/index'),
      meta: { title: '首页', icon: 'example' }
    }]
  },
  { path: '/401', component: () => import('@/views/401'), hidden: true },
  { path: '/404', component: () => import('@/views/404'), hidden: true }
]
export const asyncRouterMap = [
      {
        path: '/auth',
        component: Layout,
        redirect: '/auth/organ',
        name: 'Authoritys',
        meta: { title: '权限管理', icon: 'user-cog'},
        children: [
          {
            path: 'organ',
            name: 'Organ',
            component: () => import('@/views/organ'),
            meta: { title: '机构管理', icon: 'users', privilegs: ['organ'] }
          },
          {
            path: 'role',
            name: 'Roles',
            component: () => import('@/views/role'),
            meta: { title: '角色管理', icon: 'address-book', privilegs: ['role'] }
          },
          {
            path: 'user',
            name: 'Users',
            component: () => import('@/views/user'),
            meta: { title: '用户管理', icon: 'user', privilegs: ['user'] }
          }
        ]
      }
      { path: '*', redirect: '/404', hidden: true }
    ]

注意事项:这里有一个需要非常注意的地方就是 404 页面一定要最后加载,如果放在constantRouterMap一同声明了404,后面的所以页面都会被拦截到404,详细的问题见addRoutes when you've got a wildcard route for 404s does not work 2. 接口获取用户权限数组
通过parentId递归整理结构 用VUEX与localstage存下
权限数组第一层决定页面或者某些模块的显示, 子集决定功能的操作显示

auth = [{
  name: '首页',
  id: 1,
  child: [{
    name: '导出功能',
    id: 11
  }, {
    name: '导入功能',
    id: 12
  }]
}, {
  name: '学生',
  id: 2,
  child: [{
    name: '增加',
    id: 21
  }, {
    name: '删除',
    id: 22
  }]
}]
  1. 3.1 登录成功 根据接口返回权限数据 生成可访问路由
    3.2 页面刷新时, 根据localstage的权限 重新生成可访问路由
    3.3 若有切换角色功能时, 根据切换的角色的权限 重新生成路由

  2. 具体页面元素通过VUEX获取权限数组进行显示/隐藏操作
  3. 需要修改的主要是判断权限的业务代码部分

动态路由实现

  1. 前端路由生成由2部分组成,静态路由与动态生成路由.
    静态路由constantRouterMap由401,404,登录页等不需要权限页面组成.
    动态生成路由从路由池asyncRouterMap中,通过权限匹配筛选过滤组成.
    路由池asyncRouterMap配置如下, 在meta对象加入所需的权限数组privilegs.
    使没有权限的用户无法手敲地址进入无权限的路由, 若手敲则直接进入401提示页面
export const asyncRouterMap = [
  {
    path: '/auth',
    component: Layout,
    redirect: '/auth/organ',
    name: 'Authoritys',
    meta: { title: '权限管理', icon: 'user-cog'},
    children: [
      {
        path: 'organ',
        name: 'Organ',
        component: () => import('@/views/authority/organ/index'),
        meta: { title: '机构管理', icon: 'users', privilegs: ['organ'] }
      },
      {
        path: 'role',
        name: 'Roles',
        component: () => import('@/views/authority/role/index'),
        meta: { title: '角色管理', icon: 'address-book', privilegs: ['role'] }
      },
      {
        path: 'user',
        name: 'Users',
        component: () => import('@/views/authority/user/index'),
        meta: { title: '用户管理', icon: 'user', privilegs: ['user'] }
      }
    ]
  }
]
  1. 生成动态路通过VUEX的action实现, 每次需要生成路由是调用GenerateRoutes传入privilegs实现
// 判断是否与当前用户权限匹配
function hasPermission(privilegs, route) {
  if (route.meta && route.meta.privilegs) {
    return privilegs.some(privileg => {
      // 判断是否符合权限的业务代码
    })
  } else {
    return true
  }
}
// 递归过滤异步路由表,返回符合用户所有权限的路由表
function filterRouter(routes, privilegs, isChild) {
  const res = []
  routes.map(route => {
    const tmp = { ...route }
      if (hasPermission(privilegs, tmp)) {
        if (tmp.children) {
          tmp.children = filterRouter(tmp.children, privilegs, 1)
        }
        res.push(tmp)
      }
  })
  return res
}
actions: {
  GenerateRoutes({ commit }, data) {
    return new Promise(resolve => {
      const privilegs = data.privilegs.split(',')
      const accessedRouters = filterRouter(asyncRouterMap, privilegs, 0)
      // 存下生成的路由
      commit('SET_ROUTERS', accessedRouters)
      resolve()
    })
  }
}

调用:

// 传入用户的权限
store.dispatch('GenerateRoutes', { privilegs }).then(() => {
  router.onReady(() => {
    // store.getters.addRouters即为生成的匹配权限的路由
    router.addRoutes(store.getters.addRouters)
  })
})
  1. 配置permission.js, 判断路由切换时的是否有权限, 并做相应处理
// 判断是否有权限进入页面 permissions用户的权限数组
function hasPermission(permissions, privileg) {
  if (!privileg) return true
  return permissions.some(permission => permission.indexOf(privileg) >= 0)
}
const whiteList = ['/login'] // 不重定向白名单
router.beforeEach((to, from, next) => {
  NProgress.start()
  if (getToken()) {
    if (to.path === '/login') {
      next()
      NProgress.done()
    } else {
      // 若刷新重新读取Cookies的权限数据 生成路由
      if (store.getters.privilegs.length === 0) {
        const privilegs = getCookies('privilegs')
        // 根据权限生成可访问的路由表
        store.dispatch('GenerateRoutes', { privilegs }).then(() => {
          router.onReady(() => {
            router.addRoutes(store.getters.addRouters)
          })
          next()
        })
      } else {
        // 判断是否有权限进入页面
        if (hasPermission(store.getters.privilegs, to.meta.privilegs)) {
          next()
        } else {
          next({ path: '/401', replace: true, query: { noGoBack: true }})
        }
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next('/login')
    }
  }
})