这段时间比较忙,参与了公司一个新的B端项目的研发,从无到有搭建项目的过程中,遇到了关于项目鉴权的问题,和后端同事讨论了一下思路,自己也找了这方面的资料,整理如下文

权限管理分类:

1,菜单权限控制(页面级)

2,按钮权限控制(按钮级)

3,接口权限控制(url级别)

目前根据项目需求,实现了页面级和按钮级权限控制。

从实现思路来说,很简单,在用户输入用户名密码登录的时候,后台会返回该角色的权限集合,前端获取到录入本地存储中,建议使用sessionStorage,在生成菜单的时候通过查询sessionStorage中是否返回了该权限控制菜单展示,返回形式可以前后端协商,菜单级权限按照菜单目录返回,按钮权限通过list返回,可以是id的集合,也可以是特殊字段的集合,数据库增加一张相对应的映射表。

接下里结合实际例子来说明

首先,用户登录成功从后台获取到权限集合,在接口返回200后,获取到权限集合存入本地存储

 // 登录成功获取权限
   window.sessionStorage.setItem('menuList', JSON.stringify(res.data.menuList))
   window.sessionStorage.setItem('permissions', JSON.stringify(res.data.permissions))

菜单权限控制

菜单的构建

...
<div class="menuContent">
   <Menu :menuList="menuList"></Menu>
</div>
...

菜单组件如下:可根据自己定义数据格式修改 

<template>
  <div class="menuContent">
    <template v-for="list in menuList">
      <el-submenu v-if="list.children != undefined && list.children.length > 0 && list.show == true" :key="list.title" :index="list.path">
        <template slot="title">
          <!-- <i class="el-icon-menu"></i> -->
          {{ list.title}}
        </template>
        <Menu v-if="list.children != undefined && list.children.length > 0 && list.show == true" :menuList="list.children"></Menu>
      </el-submenu>
      <el-menu-item v-if="(list.children == undefined || list.children.length == 0) && list.show == true" :index="list.path" :key="list.title">
        {{list.title}}
      </el-menu-item>
    </template>
  </div>
</template>

<script>
export default {
  name: 'Menu',
  props: ['menuList'],
  data () {
    return {}
  },
  methods: {
  }
}
</script>
<style lang='scss' scoped>
</style>

 菜单数据格式如下:

menuList: [
        {
          path: '/overview',
          title: '首页',
          children: [],
          show: ''
        },
        {
          path: '/resource',
          title: 'a页面',
          show: '',
          children: [
            {
              path: '/physical',
              title: 'a1页面',
              show: ''
            },
            {
              path: '/logic',
              title: 'a2页面',
              show: ''
            },
            {
              path: '/pool',
              title: 'a3页面',
              show: ''
            }
          ]
        },
        {
          path: '/blockStorage',
          title: 'b页面',
          show: '',
          children: [
            {
              path: '/rbdService',
              title: 'b1页面',
              show: ''
            },
            {
              path: '/mapManagement',
              title: 'b2页面',
              show: ''
            },
            {
              path: '/client',
              title: 'b3页面',
              show: ''
            },
            {
              path: '/snapshot',
              title: 'b4页面',
              show: ''
            }
          ]
        },
        {
          path: '/object',
          title: 'c页面',
          show: '',
          children: [
            {
              path: '/objectUser',
              title: 'c1页面',
              show: ''
            },
            {
              path: '/bucket',
              title: 'c2页面',
              show: ''
            }
          ]
        }
      ]

在菜单页面js中增加方法处理

getMenu () {
      this.menuList.forEach(menu => {
        menu.show = this.hasPermiss(menu.title)
        if (menu.children.length > 0) {
          menu.children.forEach(q => {
            q.show = this.hasPermiss(q.title)
          })
        }
      })
    },
// 通过获取缓存中的菜单list比较判断是否展示该菜单
hasPermiss (val) {
      const menuArr = JSON.parse(window.sessionStorage.getItem('menuList'))
      return menuArr.some(item => item.name == val)
      // return true
    }

由于在开发过程中,前后端配置的menuList格式不统一,所以加了二次处理,如果格式统一则可以直接使用本地存储中的菜单,这样就实现了菜单的权限控制

按钮菜单控制

vue提供了自定义指令,可以通过该方法来实现按钮权限控制,核心思路不变,通过按钮处传入权限id/字符,通过遍历缓存起来的按钮权限list,判断是否拥有该权限

核心方法如下

import { checkAuthority } from '@/utils/authority'
export default {
  inserted (el, binding, vnode) {
    const { value } = binding
    const permissions = JSON.parse(sessionStorage.getItem('permissions')) || []
    const hasPermission = checkAuthority(value, permissions)
    if (!hasPermission) {
      // eslint-disable-next-line no-unused-expressions
      if (el.parentNode) {
        el.parentNode.removeChild(el)
      } else {
        el.innerHTML = ''
      }
    } else {
      el && el.setAttribute('code', value)
    }
  },
}

 关于自定义指令如何使用,可以下去自行查找,自己写出来的,印象更加深刻

Logo

前往低代码交流专区

更多推荐