这段时间比较忙,参与了公司一个新的B端项目的研发,从无到有搭建项目的过程中,遇到了关于项目鉴权的问题,和后端同事讨论了一下思路,自己也找了这方面的资料,整理如下文
权限管理分类:
1,菜单权限控制(页面级)
2,按钮权限控制(按钮级)
3,接口权限控制(url级别)
目前根据项目需求,实现了页面级和按钮级权限控制。
从实现思路来说,很简单,在用户输入用户名密码登录的时候,后台会返回该角色的权限集合,前端获取到录入本地存储中,建议使用sessionStorage,在生成菜单的时候通过查询sessionStorage中是否返回了该权限控制菜单展示,返回形式可以前后端协商,菜单级权限按照菜单目录返回,按钮权限通过list返回,可以是id的集合,也可以是特殊字段的集合,数据库增加一张相对应的映射表。
接下里结合实际例子来说明
首先,用户登录成功从后台获取到权限集合,在接口返回200后,获取到权限集合存入本地存储
代码语言:javascript复制 // 登录成功获取权限
window.sessionStorage.setItem('menuList', JSON.stringify(res.data.menuList))
window.sessionStorage.setItem('permissions', JSON.stringify(res.data.permissions))
菜单权限控制
菜单的构建
代码语言:javascript复制...
<div class="menuContent">
<Menu :menuList="menuList"></Menu>
</div>
...
菜单组件如下:可根据自己定义数据格式修改
代码语言:javascript复制<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>
菜单数据格式如下:
代码语言:javascript复制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中增加方法处理
代码语言:javascript复制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,判断是否拥有该权限
核心方法如下
代码语言:javascript复制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)
}
},
}
关于自定义指令如何使用,可以下去自行查找,自己写出来的,印象更加深刻