美文网首页前端之美-VueJsVuevue
基于vue-element-admin 的权限管理

基于vue-element-admin 的权限管理

作者: 一叶知秋_038b | 来源:发表于2019-05-08 09:54 被阅读365次

    网站链接:https://panjiachen.github.io/vue-element-admin-site/zh/guide/#%E5%8A%9F%E8%83%BD

    1.项目中要使用到权限管理及左侧菜单动态加载 基于此。
    2.项目模板使用的是vue-admin-template
    这个模板比较干净,只有框架的实现,要添加权限可以参考 github上vue-element-admin项目
    首先路由页面router:
    有2个参数
    export const constantRouterMap = [] 为初始路由参数,如登录 首页 404等共有页面 不需要权限控制的路由
    export const asyncRouterMap = []为动态路由 登录成功后 在router.beforeEach中根据后端权限 加载不同路由 已展示不同的左侧菜单

    import router from './router'
    import store from './store'
    import { Message } from 'element-ui'
    import NProgress from 'nprogress' // progress bar
    import 'nprogress/nprogress.css'// progress bar style
    import { getToken } from '@/utils/auth' // getToken from cookie
    
    NProgress.configure({ showSpinner: false })// NProgress 页面导航
    
    // 验证是否有权限
    function hasPermission(roles, permissionRoles) {
      if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
      if (!permissionRoles) return true
      return roles.some(role => permissionRoles.indexOf(role) >= 0)
    }
    
    const whiteList = ['/login', '/auth-redirect']//白名单
    
    router.beforeEach((to, from, next) => {
      NProgress.start() // start progress bar
      if (getToken()) { // determine if there has token
        /* has token*/
        if (to.path === '/login') { //如果是进入登录页面 则不需要权限 直接进入
          next({ path: '/' })
          NProgress.done() // 页面导航结束
        } else {
          if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
            store.dispatch('GetInfo').then(res => { // 拉取user_info
              store.dispatch('GenerateRoutes', res).then(() => { // 根据roles权限生成可访问的路由表
                router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
                next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
              })
            }).catch((err) => {
              store.dispatch('FedLogOut').then(() => {
                Message.error(err || 'Verification failed, please login again')
                next({ path: '/' })
              })
            })
          } else {
            // next()
            // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
            if (hasPermission(store.getters.perms, to.meta.perms)) {
              next()
            } else {
              next({ path: '/401', replace: true, query: { noGoBack: true }})
            }
            // 可删 ↑
          }
        }
      } else {
        /* has no token*/
        if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
          next()
        } else {
          next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
          NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
        }
      }
    })
    
    router.afterEach(() => {
      NProgress.done() // finish progress bar
    })
    
    

    下面为加载路由代码

    import { asyncRouterMap, constantRouterMap } from '@/router'
    // import store from '@/store'
    /**
     * 通过meta.role判断是否与当前用户权限匹配
     * @param roles
     * @param route
     */
    function hasPermission(perms, route) {  //判断是否有权限
      if (route.meta && route.meta.perms) {
        return perms.some(perm => route.meta.perms.includes(perm))
      } else {
        return true
      }
    }
    
    /**
     * 递归过滤异步路由表,返回符合用户角色权限的路由表
     * @param routes asyncRouterMap
     * @param roles
     */
    function filterAsyncRouter(routes, perms) {  //过滤没有权限的列表 循环过滤 直到没有子路由
      const res = []
      routes.forEach(route => {
        const tmp = { ...route }
        if (hasPermission(perms, tmp)) {
          if (tmp.children) {
            tmp.children = filterAsyncRouter(tmp.children, perms)
          }
          res.push(tmp)
        }
      })
      return res
    }
    
    const permission = {
      state: {
        routers: constantRouterMap,
        addRouters: []
      },
      mutations: {
        SET_ROUTERS: (state, routers) => {  //保存动态路由时 将静态路由和动态路由合并
          state.addRouters = routers
          state.routers = constantRouterMap.concat(routers)   
        }
      },
      actions: {
        GenerateRoutes({ commit }, data) {
          return new Promise(resolve => {
            const roles = data.roles
            const perms = data.perms
            let accessedRouters
            if (perms) {
              if (roles.includes(1)) {  //如果未admin角色 加载所有动态路由
                accessedRouters = asyncRouterMap
              } else {  //如果不是admin角色 则加载过滤后的动态路由
                accessedRouters = filterAsyncRouter(asyncRouterMap, perms)
              }
              commit('SET_ROUTERS', accessedRouters)  //保存路由
            }
            resolve()
          })
        }
      }
    }
    
    export default permission
    
    

    此时已经获得了想要的路由列表,定义一个获取路由的getter方法

    const getters = {
      sidebar: state => state.app.sidebar,
      device: state => state.app.device,
      token: state => state.user.token,
      avatar: state => state.user.avatar,
      userInfo: state => state.user.userInfo,
      roles: state => state.user.roles,
      perms: state => state.user.perms,
      permission_routers: state => state.permission.routers,  //路由列表
      addRouters: state => state.permission.addRouters
    }
    export default getters
    

    目录layout/sidebar/index.vue 这里是展示左侧列表的页面

    <template>
      <el-scrollbar wrap-class="scrollbar-wrapper">
        <el-menu
          :default-active="$route.path"
          :collapse="isCollapse"
          :background-color="variables.menuBg"
          :text-color="variables.menuText"
          :active-text-color="variables.menuActiveText"
          :collapse-transition="false"
          mode="vertical"
        >
          <sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path"/>   //加载这个路由就行
        </el-menu>
      </el-scrollbar>
    </template>
    
    <script>
    import { mapGetters } from 'vuex'
    import variables from '@/styles/variables.scss'
    import SidebarItem from './SidebarItem'
    import store from '@/store'
    
    export default {
      components: { SidebarItem },
      created(){
        this.perms = JSON.stringify(this.$store.state.user.perms);
      },
      data(){
        return {
          perms: ''
        };
      },
      computed: {
        ...mapGetters([
          'permission_routers',
          'sidebar'
        ]),
        variables() {
          return variables
        },
        isCollapse() {
          return !this.sidebar.opened
        }
      },
      methods: {
          
      }
    }
    </script>
    
    

    最后 来个router页面

    {
        path: '/customerInfo',
        component: Layout,
        meta: { title: '客户信息管理', perms: ['customerPage'] },  //perms是后端返回的权限标识  写到这里可以使其所有子类都加上权限 也可以分别给子类添加
        children: [
          {
            path: '/customer',
            name: 'customer',  //name必须有 面包屑导航的显示
            component: () => import('@/views/page/customerInfo/index'),  //懒加载
            meta: { title: '客户信息管理', icon: 'customerInfo' } //title左侧菜单与面包屑导航显示文字 icon为左侧菜单图标
          },
          {
            path: '/customeraddressInfo',
            hidden: true,
            name: 'customeraddress',
            component: () => import('@/views/page/customerInfo/customeraddress'),
            meta: { title: '客户公司管理', icon: 'customerInfo' }
          }
        ]
      },
      {
        path: '/fleetGroup',
        component: Layout,
        meta: { title: '车队编组管理', perms: ['fleetgroupPage'] },
        children: [
          {
            path: '',
            name: 'fleet',
            component: () => import('@/views/page/fleetGroup/index'),
            meta: { title: '车队编组管理', icon: 'fleetGroup' }
          }
        ]
      },
    

    完毕.
    感谢vue-element-admin 感谢开发其的作者 真的很方便了

    相关文章

      网友评论

        本文标题:基于vue-element-admin 的权限管理

        本文链接:https://www.haomeiwen.com/subject/qwmpoqtx.html