Vue权限控制

发表于:2020-11-14
字数统计:5.3k 字
阅读时长:13 分钟
阅读量:979

路由权限控制

所谓的页面权限控制也就是用户是否可以访问页面,页面权限包含了菜单权限和路由权限。

1、拆分路由

将路由拆分为两组数据,一组是不需要权限就能访问的,一组是需要权限才能访问的。

这里为什么要拆分路由呢?

拆分路由后一些需要权限才能访问的页面是不是没有在路由表中注册路由?,那么没有注册,那自然是不能访问了,继续往下面走。

router/index.js

// 不需要权限的路由
const routes = [
  {
    path: '/login',
    component: () => import('@/pages/login/Login'),
    meta: {
      title: '登录',
      labelPage: true
    }
  },{
    path: '/exception',
    component: Home,
    meta: {
      title: '异常页面'
    },
    children: [
      {
        path: '403',
        component: () => import('@/pages/exception/403'),
        meta: {
          title: '403'
        }
      },
      {
        path: '404',
        component: () => import('@/pages/exception/404'),
        meta: {
          title: '404'
        }
      },
      {
        path: '500',
        component: () => import('@/pages/exception/500'),
        meta: {
          title: '500'
        }
      }
    ]
  }
]

const router = new Router({
  routes
})

// 需要权限的路由
//  这里的路由其实就是之前路由中复制过来的,下面会解释如何使用
const allowRouters = [
  {
    path: '/dashboard',
    component: Home,
    meta: {
      title: '监控中心'
    },
    children: [
      {
        path: 'console',
        component: Console,
        meta: {
          title: '工作台'
        }
      }
    ]
  },
  {
    path: '/menu',
    component: Home,
    meta: {
      title: '菜单管理'
    },
    children: [
      {
        path: 'menu',
        component: () => import('@/pages/menu/Menu'),
        meta: {
          title: '菜单列表'
        }
      }
    ]
  }
]

2、获取权限列表(菜单列表)

做过权限控制的童鞋应该都知道我们的左侧菜单是根据后台生成的,那么我们的第二步就是要获取后台传递过来的权限列表。

大概是这样的一个结构

[
  {
    title: '监控中心',
    icon: '\ue6b2',
    children: [
      {
        title: '工作台',
        path: '/dashboard/console'
      }
    ]
  },
  {
    title: '菜单管理',
    icon: '\ue662',
    children: [
      {
        title: '菜单列表',
        path: '/menu/menu',
        permission: [
          {
            id: 1,
            title: '新增',
            keep_alive: 1,
            permission_mark: "menu/add"
          },{
            id: 2,
            title: '编辑',
            keep_alive: 1,
            permission_mark: "menu/edit"
          }
        ]
      }
    ]
  }
]

获取到权限列表后,下面我们要做的就是将获取到的权限列表和需要权限的路由表进行匹配,如果匹配成功,就将需要权限的路由添加到路由表里面。

其中最关键的是利用vue-router2.2.0版本新添加的一个addRoutes方法

router.addRoutes(routes)
动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。

3、匹配路由、动态注册路由

let isLoadPermission = false;

router.beforeEach((to, from, next) => {
  let { title, labelPage, keepAlive } = to.meta
  let page404 = '/exception/404'
  to.params.keepAlive = keepAlive
  let isLogin = isLoginFun()

  // 未登录
  if(!isLogin && to.path !== '/login') {
    next('/login')
  }else {
    if(!isLoadPermission) {
      // 匹配路由,将匹配成功的路由添加到路由表
      routerMatch(menuList, allowRouters).then(res => {
        router.addRoutes(res[0]);
      })
      isLoadPermission = true
    }else {
      // 打开的页面不存在
      if(to.matched.length === 0) {
        if(page404 !== from.path) {
          router.push('/exception/404')
        }
        return
      }
    }

    next()
  }
}
  
  /**
   * 根据权限匹配路由并返回
   * @param {array} permission 后台返回的权限列表(菜单列表)
   * @param {array} allowRouters 需要权限的路由表
   */
  function routerMatch(permission, allowRouters) {
    return new Promise((resolve) => {
      const routers = []
      function createRouter(permission) {
        permission.forEach((item) => {
          let { path } = item
          let pathArr = path && path.split('/')
  
          if(pathArr) {
            path = pathArr[pathArr.length-1]
          }
  
          if (item.children && item.children.length) {
            createRouter(item.children)
          }
  
          allowRouters.find((s) => {
            if (s.children) {
              s.children.find((y) => {
                if (y.path === path) {
                  y.meta.permission = item.permission
                  routers.push(s);
                }
              })
            }
            if (path && s.path === path) {
              s.meta.permission = item.permission
              routers.push(s);
            }
          })
        })
      }
  
      createRouter(permission)
      resolve([routers])
    })
  }

到这里页面级权限控制就完成了。

下面是我自己项目的权限控制页面,没有做过权限控制的小伙伴可以参考一下。

数据操作权限

这里的数据操作权限很好理解,就是不同用户权限不一样可操作的功能就不一样。

在真实的项目环境中,数据的操作权限其实还是由后台去控制的,前端只是辅助控制按钮的显示与否。

在第2步的时候我们从后台获取到了权限列表,里面有一个数组permission,存放的就是按钮权限。

[{
  title: '菜单管理',
  icon: '\ue662',
  children: [
    {
      title: '菜单列表',
      path: '/menu/menu',
      permission: [
        {
          id: 1,
          title: '新增',
          keep_alive: 1,
          permission_mark: "menu/add"
        },{
          id: 2,
          title: '编辑',
          keep_alive: 1,
          permission_mark: "menu/edit"
        }
      ]
    }
  ]
}]

获取到了按钮权限,接下来我们要做的就是控制按钮的显示与否

我们可以写一个vue自定义指令对页面中需要进行鉴权的元素进行判断:

<el-button type="primary" v-allow="'menu/add'">新建</el-button>

注册全局指令

Vue.directive('allow', {
  inserted: (el, binding, vnode) => {
    let { permission } = vnode.context.$route.meta;

    if(permission && permission.length > 0) {
      let res = permission.filter((item) => {
        return item.permission_mark === binding.value;
      });

      if(res.length === 0) {
        el.parentNode.removeChild(el)
      }
    }else {
      el.parentNode.removeChild(el)
    }
  }
})

体重+1

1/0