1. 二進位做許可權的優點 大家都知道,在Linux操作系統中,x - 可執行許可權,w - 可寫許可權 , r - 可讀許可權。其許可權值分別是1,2,4,但是有沒有想過為什麼是1,2,4 而不是 1,2,3 呢? OK , 現在是不是發現 1,2,4 分別對應著2的冪次方(2^0、2^1 、2^2),在計... ...
1、二進位做許可權的優點
大家都知道,在Linux操作系統中,x - 可執行許可權,w - 可寫許可權 , r - 可讀許可權。其許可權值分別是1,2,4,但是有沒有想過為什麼是1,2,4 而不是 1,2,3 呢?
OK , 現在是不是發現 1,2,4 分別對應著2的冪次方(2^0、2^1 、2^2),在電腦中都是以二進位的方式進行存儲,在計算時二進位的方式會更快。舉個例子:如果一個人擁有讀和寫的許可權,現在他的許可權值為6,當需要判斷他是否擁有寫許可權時,只需要用 6 和 2 進行按位與運算(6 & 2 = 2),結果非0 ,所以可以判斷擁有此許可權。當需要判斷他是否擁有可執行許可權時,同樣只需要用 6 和 1 進行按位與運算 (6 & 1 = 0 ),結果為0,所以可以判斷不擁有此許可權。
6 & 2 = 2 00000110 & 00000010 ——————---- 00000010 又或者:6 & 1 = 0 00000110 & 00000001 ——————----- 00000000
為什麼只需要用用戶的許可權值和對應的許可權進行按位與運算就可以判斷出是否擁有此許可權呢??個人理解為:當每個2的冪次方分別代表一個許可權時,剛好能夠和對應的二進位位對應起來。當用戶擁有此許可權時,對應的許可權值的二進位位會變為1,然後進行按位與運算,從而可以知道是否擁有此許可權。
用二進位的方式除了可以加快速度,還有沒有其他優點呢?如果在一個應用系統中,我們應該如何用二進位的方式來進行許可權管理呢?
想要知道二進位的方式的優勢就需要和一般方法進行比較,OK。
不採用二進位時數據表的設計: user - 用戶表 id name 1 AA 2 BB 3 CC permission表 id name method/url 1 查看帖子 get 2 發佈帖子 post 3 修改帖子 update 4 刪除帖子 delete 用戶-許可權對應表 id uid perId 1 1 1 2 1 3
採用二進位許可權方法時數據表的設計: user - 用戶表 id name per_value 1 AA 6 2 BB 7 3 CC 4 permission表 id name method/url value 1 查看帖子 get 1 2 發佈帖子 post 2 3 修改帖子 update 4 4 刪除帖子 delete 8
從上面兩張表的設計可以看出:採用二進位的方式少了一張中間表!!!它只多了兩個欄位:一個是許可權對應的許可權值,一個是用戶擁有的許可權值總和,所以可以知道——採用二進位的方式可以少一次表查詢。
按照一般方式(不採用二進位的方式)的做法是:
1.獲取當前請求的URL , 得到對應的許可權對象(或 id)
2.查看當前用戶是否含有此許可權
採用二進位的方式:獲取當前請求的URL ,得到對應的許可權對象(許可權值),用戶的許可權值 & 當前許可權的許可權值
可以看出:採用二進位的方式少了一次表查詢。
如果嫌每次請求都要去資料庫中獲取對應的許可權對象太過於麻煩,則可以把全部的許可權放入本地緩存中,因為每個請求都會進行判斷,則可以視為熱點數據,則可以放入本地緩存,從而減少資料庫查詢。這個時候:
不採用二進位的方式:每次需要去用戶-許可權對應表中判斷是否擁有相應的許可權,嫌太麻煩,可以在user裡面 用List<Integer> 裝入所有自己擁有的許可權id
採用二進位的方式:可以直接從本地緩存中取出許可權值,然後可用戶的許可權值進行判斷
- | 一般方式 | 二進位方式 |
---|---|---|
空間 | List<Integer> | long |
時間 | O(n) | O(1) |
由上列表可以看出:不管是從時間還是空間來說,二進位的方式都占有明顯的優勢!!
二、 如何用二進位做許可權
現在,可以知道用二進位的方式來做許可權擁有明顯的優勢,那麼具體的運算應該是怎樣的呢?
例子:用戶AA含有許可權值 15 , 當前許可權值 8 1. 判斷是否含有某個許可權: 15 & 8 != 0 00001111 & 00001000 ——————----- 00001000 2. 添加許可權: 15 | 8 = 15 、 15 | 16 = 31 00001111 00001111 | 00001000 00010000 —————------- -——————--- 00001111 00011111 3. 刪除某個許可權 : 15 & (~8)= 7 00001111 ~ 11110111 ————------- 00000111
現在已經知道如何具體的進行運算,但是大家有沒有一個問題:一個整型32bit 所對應的許可權是有限的,那麼應該怎麼做呢??是用long嗎??是個辦法,但是這個能夠一次性解決問題嗎??有沒有更好的辦法呢??答案是有的。
結合分級索引,可以這樣做:
可以看出:每個許可權增加了一個許可權位,用作分級,所以,現在唯一標識許可權的可以用許可權位和許可權值來進行標識。那麼這個時候:
public class User { private Integer userId; private String name; private String password; // 數組下標為0對應的值就為擁有許可權位為0的許可權值得總和 private long[] permissionSum; public boolean hasPermission(Permission permission){ int position = permission.getPosition(); long number = permission.getPermissionNum(); return !((permissionSum[position] & number) == 0); } }
每個用戶的許可權值就需要用一個數組來存儲,其下標為0的對應著許可權位為0的許可權值和。這個是不是又轉換為數據結構的問題了,所以基礎很重要嘛~