“如何控制按钮权限”,真实案例带你一步一步实现!让面试不再踩坑。

    |     2024年5月14日   |   综合资讯   |     0 条评论   |    103

后台管理系统中菜单权限用于控制菜单功能模块的操作,想更细粒度的控制增、删、改、查、搜索等基础操作,需要使用按钮权限。

在前端开发中,按钮权限指的是根据用户的角色和权限来控制界面上按钮的显示和可用性。这是一种常见的权限管理策略,用于确保用户只能访问他们有权限使用的功能。

01

后台管理按钮权限

我们先来看下真实应用场景下按钮权限是如何发挥作用的,以汇智在线系统为例。

我们给名为商城用户的角色不设置商品删除、banner删除、会员删除权限,如果以商城用户角色登录的用户就不会有商品删除、banner删除、会员删除按钮显示。

给超级管理员角色登录用户设置所有按钮操作权限。

如下图可以看到超级管理员周sir登录后在商品管理界面,具有删除商品按钮权限。

以商城用户角色登录的用户不具有删除商品按钮权限。

02

按钮权限实现

实现按钮权限有多种方式,接着我们一起来看下常用几种方式:

  • 函数方式:
<template>
  <a-button v-if="hasPermission(['20000', '2000010'])" color="error" class="mx-4"> 拥有[20000,2000010]code可见 </a-button>
</template>
<script lang="ts">
import { usePermission } from '/@/hooks/web/usePermission'
export default defineComponent({
  setup() {
    const { hasPermission } = usePermission()
    return { hasPermission }
  }
})
</script>

本质上就是通过一个统一的权限判断方法hasPermission:

export function usePermission() {
  function hasPermission(value, def = true) {
    // 默认视为有权限
    if (!value) {
      return def
    }
    const allCodeList = permissionStore.getPermCodeList
    if (!isArray(value)) {
      return allCodeList.includes(value)
    }
    // intersection是lodash提供的一个方法,用于返回一个所有给定数组都存在的元素组成的数组
    return intersection(value, allCodeList).length > 0
    return true
  }
}

很简单,从全局中获取当前用户的权限码列表,然后判断其中是否存在当前按钮需要的权限码,如果有多个权限码,只要满足其中一个就可以。

  • 组件方式

除了通过函数方式使用,也可以使用组件方式,提供了一个Authority组件,使用示例如下:

<template>
  <div>
    <Authority :value="RoleEnum.ADMIN"> <a-button type="primary" block> 只有admin角色可见 </a-button> </Authority>
  </div>
</template>
<script>
import { Authority } from '/@/components/Authority'
import { defineComponent } from 'vue'
export default defineComponent({ components: { Authority } })
</script>

包裹需要权限控制的按钮,该按钮需要的权限码通过value属性传入,接下来看看组件的实现。

<script lang="ts">
import { defineComponent } from 'vue'
import { usePermission } from '/@/hooks/web/usePermission'
import { getSlot } from '/@/utils/helper/tsxHelper'
export default defineComponent({
  name: 'Authority',
  props: { value: { type: [Number, Array, String], default: '' } },
  setup(props, { slots }) {
    const { hasPermission } = usePermission()
    function renderAuth() {
      const { value } = props
      if (!value) {
        return getSlot(slots)
      }
      return hasPermission(value) ? getSlot(slots) : null
    }
    return () => {
      return renderAuth()
    }
  }
})
</script>

同样还是使用方法,如果当前用户存在按钮需要的权限码时就原封不动渲染包裹的内容,否则就啥也不渲染。

  • 指令方式
<a-button v-auth="'1000'" type="primary" class="mx-4"> 拥有code ['1000']权限可见 </a-button>
import { usePermission } from '/@/hooks/web/usePermission'
function isAuth(el, binding) {
  const { hasPermission } = usePermission()
  const value = binding.value
  if (!value) return
  if (!hasPermission(value)) {
    el.parentNode?.removeChild(el)
  }
}
const mounted = (el, binding) => {
  isAuth(el, binding)
}
const authDirective = {
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用   mounted,
}
// 注册全局指令
export function setupPermissionDirective(app) {
  app.directive('auth', authDirective)
}

只定义了一个mounted钩子,也就是在绑定元素挂载后调用,依旧是使用方法,判断当前用户是否存在通过指令插入的按钮需要的权限码,如果不存在,直接移除绑定的元素。

03

汇智在线按钮权限
按钮权限实现方式怎么实际应用呢?这里以汇智在线系统为例详细演示它的应用。

我们采用插件方式,本质上是对指令方式的封装,耦合性上会更好。

  • 插件封装实现: 根据后端返回按钮资源数据与指令权限属性,控制按钮显示隐藏
import { useMenuStore } from '@/stores/modules/menu'

export const myPlugin = {
    // 插件封装全局组件、全局指令、全局... 
  install(app: any, options: any) {
    // 定义v-permession指令, 在 `mounted` 和 `updated` 时都调用
    app.directive('permession', (el: any, binding: any) => {
      // 1. 获取登录时存储store中的按钮资源数据
      const menuStore = useMenuStore()

      // 2. 获取当前角色资源列表 [AddProduct,EditProduct...]
      const resourceList = menuStore.resourceList

      // 3. 按钮绑定的权限值 binding.value
      const value = binding.value

      if (value) {
        const isHide = resourceList && resourceList.some(item => value.includes(item))
        if (!isHide) {
          el && el.remove()
        } else {
          console.log('need rols! Like v-perisson ="AddUser"')
        }
      }
    })
  }
}
  • 组件中使用: 商品删除按钮设置按钮权限
<el-button type="primary" size="small" v-permession="'DeleteProduct'">删除</el-button>
  • 登录成功获取按钮资源数据,保存store中
 // 调用菜单资源接口
  let menuPromise = RequestMenu(roleId)
  // 调用按钮资源接口
  let resourcePromise = RequestReourceAuthor(roleId)
  //多个promise封装的异常操作用上个方法实现 Promise.all([promise,promise]) Promise.race([promise,promise])
  const dataList: any = await Promise.all([
      menuPromise,
      resourcePromise,
  ])
  const menuData = dataList[0]
  const resourceData = dataList[1]
  if (menuData.resultCode === 1) {
      // 1.保存菜单接口数据
      this.menuList = menuData.resultInfo
      // 2.格式化菜单数据
      let routeMenuList = formateRouterMenu(menuData.resultInfo)
      // 3.添加动态路由,router对象
      routeMenuList.forEach((route: any) =>
          router.addRoute(route)
      )
  }
  if (resourceData.resultCode === 1) {
      // 保存按钮资源数据
      this.resourceList = resourceData.resultInfo.resource
  }

— end —

长按上图,识别图中二维码即可关注

推荐阅读:

动态权限菜单是什么?

封装递归组件轻松实现ElementPlus 表单组件二次封装,提高50%开发效率

ElementPlus 表格组件二次封装,提高50%开发效率

token是什么? 无感刷新token技术让项目安全性与体验性完美平衡

转载请注明来源:“如何控制按钮权限”,真实案例带你一步一步实现!让面试不再踩坑。
回复 取消