一直对权限设计很感兴趣,以前写后端代码时,搞过权限设计,挺有意思的,但是前端按钮级别的权限设计了解过,却还没具体实现过,最近项目打算对权限进行细分,先研究下前端的权限吧。
权限设计的出发点在于,让不同权限的用户,看到的内容、可实现的操作是不同的。
到具体设计上来说,可以分为路由级权限和按钮级权限,从实现的难以层度上来说,都挺简单的,这篇博客主要讲按钮级别的权限控制。
做权限控制,首先要知道要实现的目的是什么。
按钮级权限控制比较简单,根据身份不同,可以看到的按钮、可操作的功能也不相同。
首先要进行身份的区分和校验,可根据服务端下发的用户权限类别,提取出公共方法。
// ../utils/auth.js 文件位置
//获取当前客户权限
export function getCurrentAuthority(){
...
return ["admin"]
}
//校验权限
export function check(authority = []){
let current = getCurrentAuthority();
return current.some(item=>item.includes(item))
}
//登录校验
export function isLogin(){
const current = getCurrentAuthority();
return current && current[0] !== "guest";
}
抽离出公共方法进行身份提取和校验后,在不同的组件中就可以使用了,最粗暴的方法,就是直接使用 v-if
来进行疯狂的判断。
但是这种方法不优雅,而且会对原有就使用 v-if
的内容造成困扰,因此可以将权限判断进行使用上的封装,主要有两种方法,一是组件,二是指令。
既然 v-if
不太优雅,那么是否可以将 v-if
的功能封装呢,答案当然是可行的,我们只需要在需要权限控制的内容外部再嵌套上一层组件,通过外层组件来判断内层组件是否渲染,就可以实现我们所需要的 v-if
的能力。
关于这个权限组件,我们可以进行思考下。
首先,权限组件并不需要有具体的 dom 渲染,它的作用只是根据条件来判断是否来渲染它嵌套的具体业务组件。这样的话,它可以不具备 template
模板内容,只需要具体逻辑即可,这样它可以只是纯粹的函数式组件,通过引用封装好的权限校验方法,来判断props中所允许的权限。
组件实现:
思路:
通过 props 传递允许的权限,在 render 函数中,通过上下文取出 props 和 slot 插槽内容,通过 check 方法校验 props 传递的权限是否通过,根据结果渲染 slot 的内容,实现权限控制。
组件使用:
注:Authorized 组件会在多个地方使用,可以进行全局注册,具体代码不展示
使用组件方式进行权限控制,基本已经可以很好的满足我们实现按钮级权限控制的需求了,只需要在需要控制权限的按钮外面添加组件。
不过每次都需要在外面嵌套组件,还是比较繁琐的,我们可以参考下 v-if
进行自定义指令控制。
//./directives/auth.js
import { check } from '../utils/auth.js';
function install(Vue, options = {}) {
Vue.directive(options.name || 'auth', {
inserted(el, binding) {
if (!check(binding.value)) {
el.parentNode && el.parentNode.removeChild(el);
}
}
})
}
export default { install }
思路:
接收自定义指令 binding 中传递的参数,通过 check 函数进行校验,校验未通过时,获取当前指令所在节点的父节点,来删除掉当前节点,实现权限控制。
指令注册:
// main.js
import auth from './directives/auth.js'
Vue.use(auth)
指令使用:
使用组件方式来实现权限控制,在权限修改后会比较灵活的渲染受控部分,同时使用时候会稍微繁琐;
指令方式实现的权限控制,使用起来会比较简洁,但是是通过删减 dom 节点的方式实现的,因此只有在第一次时控制。
权限在赋予后,不会随意变动,可以根据使用场景来选用两种不同的方式。
1. Vue 函数式组件
2. 自定义指令