Permission design based on bit operation
Since the permissions here are based on Bit, everyone needs to have a certain understanding bit and bit operators.
[TOC]
Pre-knowledge
- MDN bit operator
- single permission has and only one is 1
- From right to left, from low to high
Operator shorthand:
&
bitwise AND: if the corresponding bit is all 1, it is 1|
bitwise OR: if the corresponding bits are all 0, then it is 0^
Bitwise XOR: 0 if the corresponding bits are the same, and 1 if they are different
actual case
Let's take four types of CRUD as an example, using 4-bit bits. One thing to note here, a single permission and only one is 1
variable | Binary | describe |
---|---|---|
C | 0b0001 | increase |
D | 0b0010 | delete |
U | 0b0100 | change |
R | 0b1000 | check |
Check certain permissions
const curPermission = 0b1001; // 当前用户的权限,「增」「查」
const allowCreate = (curPermission & C) === C; // => true
const allowUpdate = (curPermission & U) === U; // => false
From the above code, we can see that the current user's authority is Ob1001
. The first and fourth places are 1
, which means that they have and
.
When the user's permission uses bitwise AND, only the same bit is 1 to get 1
As can be seen from the figure and the code, we can use &
to compare whether the defined variables are equal to know whether there is a certain permission currently
Add a permission
let curPermission = 0b0100; // 当前用户只有「改」权限
// C = 0b0001 D = 0b0010
// 添加「增」「删」的权限
curPermission = curPermission | C | U; // => 0b0111
In the end, the permissions we got include the original "change" and the newly added "add" and "delete"
Delete a permission
When deleting, we use the bitwise inversion and then bitwise and &(~P)
operations
let curPermission = 0b1110; // 当前用户权限,「删」「改」「查」
// R = 0b1000
curPermission = curPermission & ~C; // => Ob0110 删除了「查」的权限
In the end, the only permissions we got were "delete" and "modify", and the "check" permission has been deleted
Toggle operation
Use bitwise XOR if there is nothing, then increase and decrease (the corresponding bit is different is 1, the same is 0) , judging from the result, it is actually a toggle operation
let curPermission = 0b1000; // 当前用户权限,「查」
// 无则增;C = 0b0001
curPermission ^ C; // => Ob1001 得到的为「增」「查」
// 有则减
curPermission ^ C; // => Ob1001 得到的为「查」,又将「增」权限删除了
Compound type
We can use compound operations to perform more convenient and quick operations, which can be used for any of the above operations, here only verification is used as an example
When our page has the operation column in the figure below, and the delete button also modifies the button, the following situations will occur:
Delete
button when there is "delete" permissionEdit
button when there is "change" permission- Hide the
operation
column when there is no "delete" or "change"
const curPermission = 0b1000; // 当前用户权限
const D = 0b0010; // 删
const U = 0b0100; // 改
const DandU = 0b0110; // 删、改 都有
const allowDelete = (p: number) => (p & D) === D;
const allowUpdate = (p: number) => (p & U) === U;
const allowDeleteAndUpdate = (p: number) => (p & DandU) === DandU;
const COLUMNS = [
{
title: 'operation',
dataIndex: 'operation',
render: () => (
<>
{allowUpdate(curPermission) && <button>Edit</button>}
{allowDelete(curPermission) && <button>Delete</button>}
</>
),
},
];
const retColumns = COLUMNS.filter((x) => {
if (x.dataIndex === 'operation') {
return allowDeleteAndUpdate(curPermission);
}
return true;
});
// retColumns 是我们最终使用的 Table columns 数据
In the same way, the composite type in the code can be applied to other operations, and students who are interested in homework can code
advantage
- One parameter can represent multiple types, no multiple permission codes are required
- Compound types can be used. For example, if there are both new additions and modifications, you can define
cosnt allowCreateAndUpdate = 0b1010
, and when used,(curAccess & allowCreateAndUpdate) === allowCreateAndUpdate
- High scalability, such as adding another executable permission, you can use 5-bit bit 0b10000
shortcoming
Bitwise operator treats its operand as a 32-bit binary string - from MDN
In this case, the number of available permissions is limited, and you can use the structure or the
namespace to control
The structure is the object, we put the specific permissions in the defined structure
const permissionList = [
{
pid: 1, // position id 也就是 位置ID
code: 0b0001, // 对应的编码
}
];
Namespace, in fact, can also use the above structure description, here we use strings to describe, there is a set of default rules: pos,code
const permissionList = ['pos1,0b0001', 'pos2,0b0011'];
In the specific use, compile the operation method corresponding to the corresponding authority according to your own different rules, and provide it to the specific business students.
TypeScript bonus
Static methods using Enum and bit assignment operators and namespace
/** 定义 */
enum AuthCode {
Read = 0b001, // 也可以写成 1
Write = 0b010, // 也可以写成 r << 1 或 2
/** 执行 execute */
Exec = 0b100, // 也可以写成 r << 2 或 4
// 以下为复合类型
/** 0b011 */
ReadAndWrite = 0b011,
/** Union of all host auth */
HostAuthMask = 0b111,
}
namespace Auth {
/**
* 验证当前权限是否存在
* @param validCode - 要验证的权限编码(即用户返回的编码)
* @param code - 定义好的权限编码
*/
export const validator = (validCode: AuthCode, code: AuthCode): boolean => {
return (validCode & code) === code;
};
// curry 处理 validator()
/**
* 给用户加入权限
* @param userCode - 当前用户拥有的权限
* @param waitingCode - 待加入给用户的权限
* @returns 返回加入权限后的所有权限
*/
export const add = (
userCode: AuthCode,
waitingCode: AuthCode | AuthCode[]
): AuthCode => {
let code: number;
if (Array.isArray(waitingCode)) {
code = waitingCode.reduce((acc, cur) => {
return acc | cur;
}, 0);
} else {
code = waitingCode;
}
return userCode | code;
};
/**
* 删除用户的权限
* @param userCode - 当前用户拥有的权限
* @param rmCode - 要删除的权限
*/
export const remove = (
userCode: AuthCode,
rmCode: AuthCode | AuthCode[]
): AuthCode => {
let code: number;
if (Array.isArray(rmCode)) {
code = rmCode.reduce((acc, cur) => {
return acc | cur;
}, 0);
} else {
code = rmCode;
}
return userCode & ~code;
};
/**
* 用户权限 Toggle
* @description 无则增,有则减
* @param userCode - 当前用户拥有的权限
* @param tglCode - 要 toggle 的权限
*/
export const toggle = (userCode: AuthCode, tglCode: AuthCode) => {
return userCode ^ tglCode;
};
}
// test validator
// const userCode = 0b011; // 获取到用户在当前页的权限码(读、写)
// console.log(Auth.validator(userCode, AuthCode.Read)); // => true; 当前用户拥有 读 权限
// console.log(Auth.validator(userCode, AuthCode.ReadAndWrite)); // => true; 当前用户拥有 读写 权限
// console.log(Auth.validator(userCode, AuthCode.Exec)); // => false; 当前用户没有 执行 权限
// console.log(Auth.validator(userCode, AuthCode.Read | AuthCode.Exec)); // => false; 当前用户没有 读,执行 权限;两个权限都有才为真
// test add
// let userCode = 0b000; // 获取到用户在当前页的权限码(无权限)
// console.log((userCode = Auth.add(userCode, AuthCode.Read))); // => 1 === 0b001; 给当前用户加入 读 权限
// console.log(Auth.validator(userCode, AuthCode.Read)); // => true; 验证当前用户已经拥有 读 权限
// console.log(Auth.validator(userCode, AuthCode.Write)); // => false; 验证当前用户没有 写 权限
// console.log((userCode = Auth.add(userCode, [AuthCode.Write, AuthCode.Exec]))); // => 7 === 0b111; 给当前用户加入 写、执行 权限
// console.log(Auth.validator(userCode, AuthCode.HostAuthMask)); // => true; 验证当前用户拥有所有权限
// test remove
// let userCode = 0b111; // 获取到用户在当前页的权限码(所有权限)
// console.log(Auth.validator(userCode, AuthCode.HostAuthMask)); // => true; 验证当前用户有所用权限
// console.log((userCode = Auth.remove(userCode, AuthCode.Read))); // => 6 === 0b110; 移除用户 读 权限
// console.log(Auth.validator(userCode, AuthCode.Read)); // => false; 验证当前用户已经删除 读 权限
// console.log(
// (userCode = Auth.remove(userCode, [AuthCode.Write, AuthCode.Exec]))
// ); // => 0 === 0b000; 移除用户 读、执行 权限
// console.log(Auth.validator(userCode, AuthCode.Write)); // => false; 验证当前用户已经删除 写 权限
// console.log(Auth.validator(userCode, AuthCode.Exec)); // => false; 验证当前用户已经删除 执行 权限
// test toggle
// let userCode = 0b101; // 获取到用户在当前页的权限码(执行、读)
// console.log((userCode = Auth.toggle(userCode, AuthCode.ReadAndWrite))); // => 6 === 0b110; 当前用户删除了 读,添加了 写(写 无则增,读 有则减)
// console.log(Auth.validator(userCode, AuthCode.Read)); // => false; 验证当前用户无 读 权限
// console.log(Auth.validator(userCode, AuthCode.Write)); // => true; 验证当前用户有 写 权限
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。