二进制一般能表示32个状态,每一个位上都可以表示不同的权限值,假设我们有四个权限值,分别是增删改:
enum Permission {
Create = 0b0001, // 新增
Delete = 0b0010, // 删除
Update = 0b0100, // 修改
}
有了权限值之后,我们就可以用位运算来对权限值进行组合,对应位为1则为有权限,0则没有
涉及到到的位运算前置知识:
新增权限-按位或|
按位或运算是都为0为0,有一个1就是1,所以没权限时对应位为0,按位或上权限值对应位上就是1了
移除权限-按位异或^
按位异或运算是相同为0不同为1,所以对应位上的权限是1,要移除的权限值也是1,两者相同对应位上就是0了,这里介绍一下按位或,但是没有使用它,采用了另一种更好的方式,见代码
判断是否有某个权限-按位与&
按位与运算是都为1为1,有一个0就是0,所以有权限的话对应位按位与上权限值结果肯定是1,如果对应位上是0那么结果就是0,判断是否有权限只看结果是否不等于0即可
权限操作代码:
enum Permission {
Create = 0b0001,
Delete = 0b0010,
Update = 0b0100,
}
const NotHavePermission = 0 // 没有权限
/**
* @description 组合权限
* @param userPermission 用户的权限散列值
* @param permission 要组合的权限
* @return 如果包含要移除的权限则返回被移除的权限,否则返回null
*/
const combineRolePermissions = (
userPermission: number,
...roleList: Permission[]
): number => {
return roleList.reduce((prev, curr) => {
if (!hasPermission(prev, curr)) {
prev = curr | prev // | 是有一个是0就是0 都为1则为1
}
return prev
}, userPermission)
}
/**
* @description 移除权限
* @param userPermission 权用户的权限散列值
* @param permission 要移除的权限
* @return 如果包含要移除的权限则返回被移除的权限,否则返回null
*/
const removePermission = (
userPermission: number,
targetPermission: Permission
): number | null => {
if (!hasPermission(userPermission, targetPermission)) {
return null
}
// 异或相同为0不同为1 所以都是1则那位变成0就删除了
// return userPermission ^ targetPermission; // 异或可以删除但是得先判断是否有该权限,如果当userPermission为0000时不会删除,所以用第二种方式不会出现这种问题
return (userPermission &= ~targetPermission) // react源码里移除也是这么做的
}
/**
* @description 是否有某个权限
* @param userPermission 权用户的权限散列值
* @param targetPermission 是否包含的权限
* @returns
*/
const hasPermission = (
userPermission: number,
targetPermission: Permission
): boolean => {
return (userPermission & targetPermission) !== NotHavePermission // &就是有一个为1就是1 都为0则为0
}
let userPermission = NotHavePermission // 用户初始化权限是什么都没有就是0
// 后端返回的权限集合
const permissionCollections = [Permission.Create, Permission.Update]
// 组合后端返回的权限
userPermission = combineRolePermissions(
userPermission,
...permissionCollections
)
console.log('用户权限:', userPermission.toString(2)) // 0101
console.log('是否有删除权限', hasPermission(userPermission, Permission.Delete)) // false
userPermission = removePermission(userPermission, Permission.Create) // 移除新增权限
console.log('删除新增后:', userPermission.toString(2)) // 0100
这样设计的好处就是我们可以任意的组合权限值,比如用户既能新增又能修改,那么组合Create和Update即可表示,新增和移除都很灵活, 不管是不同操作类型的权限控制还是页面的访问权限控制都很方便,二进制32位能表示32个页面,64位系统能表示64个页面,我们平时的应用位数基本上够用了