使用二進位制位來控制許可權,表設計

2021-09-27 01:25:14 字數 3680 閱讀 5379

最近在自己搭建乙個管理後台,到了許可權角色的時候,按常規涉及了以下幾張表:

也是相當常見的模型了。

但是隨機我發現乙個不大不小的問題,當許可權表/資源表稍微大一點的時候,角色關聯許可權tbl_role_permission就會有大量資料

這才乙個角色,很傷腦筋。於是我想到了上個專案中用到的二進位制表示許可權方法。

二話不說,看表

我們知道乙個long型別,可以轉為64位的二進位制型別,也就是說,0l就是

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

如果把每乙個位置bit_pos表示乙個許可權,除去最左邊的符號位以外,可以表示63個許可權或資源,也就是一條tbl_role_permission關聯記錄就可以表示63中不同許可權。

其實按正常系統來說,63中許可權、資源是肯定不夠的,這時候就用bit_group來區分,超過63則劃入另乙個group。

也就是通過group和bit_pos來確定乙個許可權。

那麼tbl_role_permission就會是這樣:

只是可讀性變差了一些,但是關聯看起來更簡潔了

現在角色和許可權通過乙個二進位制來關聯,那麼怎麼給乙個角色新增許可權和刪除許可權呢?

增加使用二進位制的位運算,比如 現在乙個角色的許可權是 bit_group是 0, bit_str是00001111,要加入乙個 bit_group是 0,bit_pos是5的許可權 (這裡bit_pos是從0開始,為了符合程式的索引下標規則)

規則如下

原二進位制位許可權 | 要新增的許可權二進位制位

首先得到許可權的bit_str: 用到位運算的左移運算

1

<< bit_pos

1 << 5 = 00100000

再和00001111 進行或運算

00100000

|00001111

=00101111

刪除

刪除許可權也很簡單,還是上面的00101111,如果要把剛剛的bit_group是 0,bit_pos是5的許可權刪掉

還是先拿到二進位制位

1 << 5 = 00100000

然後原二進位制位許可權 & (~ 要刪除的許可權二進位制位)

也就是00101111 & (~ 00100000)

~ 00100000 也就是 11011111

再進行與運算

00101111

&11011111

=00001111

判斷是否具有許可權

為什麼採用二進位制來表示許可權,還有乙個便利就是可以簡單的判斷這個許可權屬不屬於這個角色的許可權集合

如果乙個角色的許可權集合是 00001111,判斷bit_pos是2的是不是這個許可權集合:

原二進位制許可權集合 & ( 要判斷的許可權二進位制 ) == 要判斷的許可權二進位制

1 << 2 = 00000100

boolean b =

00001111

&00000100

==00000100

很明顯判斷結果為true

合併許可權

要合併兩個許可權,不用擔心重複的問題了,直接與運算

原許可權 | 新許可權

說了這麼多,怎麼連表查詢角色對應的許可權集合呢?

根據角色名查許可權

select

*from

tbl_role r

left

join tbl_role_permission rp on r.id = rp.role_id

left

join tbl_permission p on p.bit_group = rp.permission_bit_group

where

conv(rp.permission_bit_str,2,

10)>> p.bit_pos &1=

1and r.role_name = ?

;

這個where條件其實就是將bit_str的許可權集合,比如00001111,右移bit_pos,和1進行與運算,其實還是判斷bit_str在第bit_pos個索引位置是不是1,是則有這個索引位置的許可權,否則沒有

介紹兩個mysql方法

conv():

conv(n,from_base,to_base) 表示轉換進製, n是列名或值, from_base是從什麼進製,to_base是轉到什麼進製

conv(rp.permission_bit_str,2,10) 就是從二進位制的01串變成十進位制的數

bin():

bin(n) ,n是列名或值,將該值從10進製轉成二進位制,但是前面的0會忽略

lpad():

lpad(n,len,s),n是列名或值,len是總長度,s是當n長度不夠len時,使用s來填充左邊補全長度

所以如果我們想得到某個十進位制的二進位制位,

根據許可權名查詢角色

其實差不多

select

*from

tbl_permission p

left

join tbl_role_permission rp on p.bit_group = rp.permission_bit_group

left

join tbl_role r on r.id = rp.role_id

where

conv(rp.permission_bit_str,2,

10)>> p.bit_pos &1=

1and p.

`name`

= ?

總之用二進位制來代表許可權,乙個明顯的好處就是原本63條資料庫記錄都可以用一條記錄代替。而且判斷使用者許可權的時候,不用從幾十上百條許可權裡,乙個個遍歷判斷進行鑑權。只需要進行乙個二進位制位運算就可以了。直接位運算一般都是比平時的**要高效的。

缺點,表查詢更複雜了,原本直接關聯表id查詢就可以,現在需要進行各種轉換和運算。而且這個設計在工作交接的時候,還得需要詳細交代bit_group和bit_pos是什麼,有什麼用,**上的可讀性也受影響了,容易看懵

二進位制許可權控制

在許可權分配中有多個許可權級別,不同使用者分別有多個不同的許可權。論壇的許可權 檢視 發帖 投票 搜尋 使用者的許可權 使用者a 檢視 發帖 使用者b 檢視 使用者c 檢視 發帖 投票 搜尋 分析 有四種不同的許可權級別,總共2 4種許可權分配方式。像這樣許可權等級劃分和不同級別使用者的許可權分配採...

二進位制許可權

package test 二進位制許可權使用 許可權 0 表示所有許可權 1 新增 0001 2 修改 0010 4 刪除 0100 8 檢視 1000 如 10 十進位制的 10 不是二進位制的 1 代表的許可權是 修改和檢視許可權 public class bitpermission 是否含有許...

二進位制位運算

與運算,6 3 2 或運算 6 3 7 異或運算 6 3 5 反碼 6 7 左移 3 2 12 3 2 2 12 右移 3 1 1 3 2 1 無符號右移 3 1 1 3 2 1 按位與,當兩位同時為1時才為1如 1 1 1 1 0 0 0 1 0 6 3相當於 0110 0011 0010 2 按...