使用场景:

web后台项目都会有权限控制,可以分为两类,分别为页面权限操作权限

  • 页面权限:是指当前账号是否可以看到此页面;
  • 操作权限:是指当前账号在此页面可以做哪些操作

很显然,账号必须先要能看到此页面,才能说在此页面能做的操作。如果连页面都看不到,具有的操作毫无意义,一般查看操作就是页面的权限,只能分配了查看操作的权限,才能在此页面进行其它操作。

本文章只探讨操作权限的解决方案,页面权限后面再新建文章

账号权限控制分类:

账号权限控制主要分为账号具有的角色账号具有的权限标识

  • 角色 : 一个账号可以绑定多个角色,例如useradmintest等,不同的角色拥有不同的权限标识
  • 权限标识: 一个为有权限的操作,例如sys:user:selectsys:user:add分别表示可以对用户管理这个页面进行查看及新增操作。

前端可以根据这两个权限信息来校验用户具有的页面权限操作权限

例如(权限标识控制)

一个用户管理页面,分别有查询、新增、修改、删除四个操作,且新增、修改、删除分别对应一个操作按钮,此4个操作分别对应的权限标识为sys:user:selectsys:user:createsys:user:updatesys:user:delete。当登录的账号具有sys:user:select权限标识时,才可以看到此页面,否则无法进入此页面。

  • 当用户具有sys:user:create权限标识时,才能看到(或者启用)新增按钮,实现新增操作。否则此按钮隐藏(或者禁用)

  • 当用户具有sys:user:update权限标识时,才能看到(或者启用)更新按钮,实现更新操作。否则此按钮隐藏(或者禁用)

  • 当用户具有sys:user:delete权限标识时,才能看到(或者启用)删除按钮,实现删除操作。否则此按钮隐藏(或者禁用)

这样同一个管理后台,不同权限的账号登录进来看到的效果及其操作都是不一样的

角色控制也是相同的原理。比如user角色具有查看更新的权限,admin具有全部的操作权限

复杂场景

一个操作,需要多个接口才能完成。还是以用户管理举例,例如搜索条件有部门的下拉框,而下拉框中的数据是通过调用接口来得到的。那么查询这个操作,除了sys:user:select权限标识外,还需要sys:org:list权限标识。新增操作也是如此,新增用户的时候也需要选择部门信息,那么除了sys:user:create权限标识外还需要其它权限标识才能完整的实现操作。

总结:

  1. 权限标识一般和后台接口绑定,一个权限标识对应一个接口
  2. 一个操作可能需要多个接口才能完成功能

前端操作权限的本质

对于前端而言,操作权限的本质就是校验账号的具有的角色或者权限标识是否具有此按钮(或者dom)需要的角色或者权限标识,通过这个校验的结果来控制删除/禁用按钮(或者dom)或者显示/启用按钮(或者dom)

例子

例如有一个新增的按钮,需要有sys:user:create权限标识才能看到此按钮,伪代码如下

  if(isPerms('sys:user:create')){<!-- 有权限,显示按钮  --><button>新增用户</button>}else{<!-- 没有权限不显示按钮  -->}

从上面的结果来看,需要我们收到的操作dom元素,实现对dom的显示/隐藏或者启用/禁用。

解决方案

用vuex存储用户的所有角色及权限标识,并封装成判断的方法,VUE实例上挂载全局属性方法,方便所有组件调用,同时封装自定义指令,指令中的判断逻辑也是调用此判断方法。

权限校验工具方法

permissionUtils.js

/*** 权限校验工具*/
import store from "@/store";/*** 权限校验的类型* @type {{ROLE: string, PERMS: string}}*/
export const PermTypeEnum = {PERMS: 'perms',ROLE: 'role'
}/*** 权限校验的操作* @type {{OR: string, AND: string}}*/
export const CheckOperateEnum = {AND: 'and',OR: 'or'
}/***  检查是否具有全部资源权限* @param checkPerms {Array<String>}  检查的资源* @param allPerms {Array<String>}   具有的资源* @returns {Boolean}  true 具有权限  false 没有权限*/
export const checkPermsAll = (checkPerms, allPerms) => (checkPerms || []).every((perm) => allPerms.includes(perm))/***  检查是否具有任意资源权限* @param checkPerms {Array<String>}  检查的资源* @param allPerms {Array<String>}   具有的资源* @returns {Boolean}  true 具有权限  false 没有权限*/
export const checkPermsAny = (checkPerms, allPerms) => (checkPerms || []).some((perm) => allPerms.includes(perm))/*** 权限校验* @param checkPerms {String|Array} 需要检查的权限* @param permType  权限的类型,角色或者权限标识* @param checkOperate  操作类型,且或者 是 或* @returns {Boolean}   是否具有权限, true 有权限, false 无权限*/
export const checkPermissions = (checkPerms,permType = PermTypeEnum.PERMS,checkOperate = CheckOperateEnum.AND) => {//得到用户具有的权限集合const perms = store.getters.perms// 得到用户具有的角色集合const roles = store.getters.roles.map(role => role.roleId)//权限判断结果const allPerms = []//开始判断是 角色权限校验 还是 权限校验 , 再判断是 或 操作 还是 与 操作if (permType === PermTypeEnum.ROLE) {allPerms.push(...roles)} else {allPerms.push(...perms)}//这里需要对校验的权限标记或者角色进行转换为数组const needCheckPerms = []if (checkPerms) {if ((checkPerms instanceof Array) && (checkPerms.length > 0)) {//如果输入数据为数组,则直接加入needCheckPerms.push(...checkPerms)} else if ((typeof checkPerms) === 'string') {needCheckPerms.push(checkPerms)}}let hasPerm = false;// 如果包含特殊标识,则视为管理员,全部放行if (allPerms.includes('*')) {hasPerm = true;} else {// 判断是 或 操作 还是 与 操作 , 如果给了or的修饰符,则表示为任意权限if (checkOperate === CheckOperateEnum.OR) {hasPerm = checkPermsAny(needCheckPerms, allPerms)} else {hasPerm = checkPermsAll(needCheckPerms, allPerms)}}return hasPerm;
}export default {PermTypeEnum,CheckOperateEnum,checkPermissions
}

挂载到全局属性

这里可以想到vue提供的v-if指令,再结合全局方法属性配合实现,在全局方法属性中提供权限校验,用v-if指令来实现操作dom。
例子如下:

import {checkPermissions} from "@/utils/permissionUtils";
/*** 挂载全局 权限判断函数*/
Vue.prototype.isPerms = checkPermissions

使用

 <button v-if="isPerms(['sys:user:create','sys:org:list'])">新增用户</button>

此方案可以实现,但过于单一,不过灵活。如果需要扩展角色权限校验或者采用任意权限无法很好的扩展。

自定义权限指令 (推荐)

注册vue的自定义指令,在自定义指令的钩子函数中提供绑定的参数及其dom,这样就可以进行dom操作。在自定义指令中dom元素挂载在父dom后,进行权限校验,如果权限不满足,则删除此dom
自定义指令代码如下:

import {CheckOperateEnum, checkPermissions, PermTypeEnum} from '@/utils/permissionUtils'/*** 权限校验命令,支持:* * 角色权限校验* * 权限标识校验* * 输入为字符串或者数组* * 任意权限或者全部权限校验* 使用例子 :*  权限标识校验:*    全部存在  v-permission="['sys:user:create','sys:user:list']" 或者 v-permission="'sys:user:create'"*    任意存在  v-permission.or="['sys:user:create','sys:user:list']"**  角色权限校验:*    全部存在  v-permission:role="['user1','user2']" 或者 v-permission="'user'"*    任意任意  v-permission:role.or="['user1','user2']"**/
export default {//被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)/*el:指令所绑定的元素,可以用来直接操作 DOM。binding:一个对象,包含以下 property:name:指令名,不包括 v- 前缀。value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。*/inserted(el, binding, vnode) {// 得到指令的绑定值,此值为js计算完成后的值,当前为需要的权限const {value, arg, modifiers} = bindingif (value) {//权限判断结果 , 这里会处理字符串及数组的情况const hasPermission = checkPermissions(value,(arg === 'role') ? PermTypeEnum.ROLE : PermTypeEnum.PERMS,modifiers.or ? CheckOperateEnum.OR : CheckOperateEnum.AND)if (!hasPermission) {//如果没有权限则直接删除此节点el.parentNode && el.parentNode.removeChild(el)}} else {throw new Error(`缺少权限标识 例如 v-permission="['sys:user:create','sys:user:list']" 或者 v-permission:role="['user']" `)}}
}

挂载指令

  Vue.directive('permission', permission)

使用例子

  <div v-permission:role.or="['admin','role']"><span>admin和role角色都能看到我</span></div><div v-permission:role="['admin','user']"><span>必须同时有admin和user角色才能看到</span></div><div v-permission="['sys:user:select','sys:org:list']"><span>必须同时有sys:user:select和sys:org:list权限标识才能看到</span></div><div v-permission.or="['sys:user:select','sys:org:list']"><span>sys:user:select和sys:org:list权限标识都能看到我</span></div>

VUE自定义指令-权限校验相关推荐

  1. vue 自定义指令 权限指令

    目前项目中需要做到按钮级别的控制,所以想到了自定义指令来实现,在自定义指令中来控制组件的显示于隐藏. 1.第一步创建自定义指令 js 文件: permission.js 2.在main.js中直接引入 ...

  2. clientsideevents能定义几个click事件_分享8个非常实用的Vue自定义指令

    作者:lzg9527 https://juejin.cn/post/6906028995133833230 在 Vue,除了核心功能默认内置的指令 ( v-model 和 v-show ),Vue 也 ...

  3. Vue自定义指令介绍及原理

    Vue自定义指令 Vue指令: 在使用Vue框架进行前端开发时,我们经常会使用一些特殊指令来快速实现一些效果或功能. 常见指令如:v-bind.v-if (v-else).v-show.v-html等 ...

  4. vue自定义指令封装节流_Vue自定义指令封装节流函数的方法示例

    节流函数是web前端开发中经常用到的一个开发技巧,在input实时搜索,滚动事件等,为了避免过多消耗性能,我们都会使用节流函数.在<JavaScript高级程序设计>一书中有这样的一个例子 ...

  5. vuejs 指令封装 button 加载效果_这些Vue自定义指令,让你的项目开发爽到爆

    受 AngularJS 的启发,Vue 内置了一些非常有用的指令(比如v-html 和 v-once等),每个指令都有自身的用途.完整的指令列表可以在这里查看. 这还没完,更棒的是可以开发自定义指令. ...

  6. vue 自定义指令(directive)实例

    一.内置指令 1.v-bind:响应并更新DOM特性:例如:v-bind:href  v-bind:class  v-bind:title  v-bind:bb 2.v-on:用于监听DOM事件: 例 ...

  7. pyqt5 treeview鼠标右键菜单事件_【动手实践】使用 Vue 自定义指令实现右键菜单...

    本文来自于 神奇的程序员 前言 浏览器里右键时会有一个默认的菜单,在我的开源项目中正好有自定义右键菜单的需求,在npm库找了下与之相关的包,发现都是以组件形式实现的,感觉那种做法太过繁琐. 于是,我就 ...

  8. html标签outclick,vue自定义指令(Directive中的clickoutside.js)的理解

    阅读目录 vue自定义指令clickoutside.js的理解 vue自定义指令请看如下博客: 一般在需要 DOM 操作时我们都需要使用自定义指令的方式去实现,当然一些特殊的事件监听也可以使用指令,例 ...

  9. 9、Vue自定义指令

    Vue自定义指令 1.vue指令和自定义指令 2.使用自定义指令 2.1.全局注册 2.2.局部注册 3.钩子函数 1.vue指令和自定义指令 什么是指令? v-model.v-bind.v-on.v ...

最新文章

  1. LeetCode 3Sum
  2. Android中Intent的显示和隐式使用
  3. Android之让代码跑在主线程(无context上下文)的封装
  4. 云架构师是做什么的_为什么以及如何成为云架构师
  5. string与string.h的区别
  6. SpringBoot指南(三)——静态资源、欢迎页、Favicon、默认页面
  7. 为什么我会弃Java,选择了Kotlin——专访《Java编程思想》作者 Bruce Eckel
  8. CSS基础——CSS 列表和表单【学习笔记】
  9. dumpsys gfxinfo packacges计算帧率
  10. pandas中read_csv的缺失值处理
  11. Gerald and Giant Chess
  12. ASP.NET2.0 ReportingServices,报表灵魂的收割者(一)【月儿原创】
  13. HttpEntity的类型及其使用(各种继承的使用)
  14. oracle 抽样_利用ORACLE实现数据抽样(sample block)
  15. Python Flask Web 框架入门
  16. PTA 7-47 打印选课学生名单分数 25 分 (C 邻接表+二叉排序树 )
  17. 用docker跑机器学习环境
  18. 什么是重绘,重排?如何解决?
  19. Microsoft Office Word使用技巧(各种报告论文排版可能需要的小技巧)
  20. 股权控制权的五种设计策略

热门文章

  1. 喜报|众享比特成为“TBI能源区块链组”首批成员
  2. linux and windows 双系统启动(详细情况分类说明)
  3. 你的思想决定你的高度
  4. 大健康和大数据助推绿色发展
  5. 【数字化】数字化工厂2020:塑造制造业的新未来
  6. webUploader的使用
  7. Mac Book PRO 安装WIN10
  8. 机器学习实战 学习记录 (4-5章)
  9. 【博客177】二进制中1的个数:方法三
  10. 机器人控制器编程课程-教案06-理论课总结