使用二进制位来控制权限,表设计
前言
最近在自己搭建一個管理后臺,到了權限角色的時候,按常規涉及了以下幾張表:
也是相當常見的模型了。
但是隨機我發現一個不大不小的問題,當權限表/資源表稍微大一點的時候,角色關聯權限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 << 5 = 00100000
再和00001111 進行或運算
刪除
刪除權限也很簡單,還是上面的00101111,如果要把剛剛的bit_group是 0,bit_pos是5的權限刪掉
還是先拿到二進制位
1 << 5 = 00100000
然后
原二進制位權限 & (~ 要刪除的權限二進制位)
也就是
00101111 & (~ 00100000)
~ 00100000 也就是 11011111
再進行與運算
判斷是否具有權限
為什么采用二進制來表示權限,還有一個便利就是可以簡單的判斷這個權限屬不屬于這個角色的權限集合
如果一個角色的權限集合是 00001111,判斷bit_pos是2的是不是這個權限集合:
原二進制權限集合 & ( 要判斷的權限二進制 ) == 要判斷的權限二進制
1 << 2 = 00000100
很明顯判斷結果為true
合并權限
要合并兩個權限,不用擔心重復的問題了,直接與運算
原權限 | 新權限
查詢sql
說了這么多,怎么連表查詢角色對應的權限集合呢?
根據角色名查權限
這個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來填充左邊補全長度
所以如果我們想得到某個十進制的二進制位,
根據權限名查詢角色
其實差不多
總結
總之用二進制來代表權限,一個明顯的好處就是原本63條數據庫記錄都可以用一條記錄代替。而且判斷用戶權限的時候,不用從幾十上百條權限里,一個個遍歷判斷進行鑒權。只需要進行一個二進制位運算就可以了。直接位運算一般都是比平時的代碼要高效的。
缺點,表查詢更復雜了,原本直接關聯表id查詢就可以,現在需要進行各種轉換和運算。而且這個設計在工作交接的時候,還得需要詳細交代bit_group和bit_pos是什么,有什么用,代碼上的可讀性也受影響了,容易看懵
總結
以上是生活随笔為你收集整理的使用二进制位来控制权限,表设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 亲友定位助手--具备实时共享位置的智能手
- 下一篇: 基于简单的机器学习方法等异常值识别方法(