實現數據權限控制的一種方法


在企業管理系統中,常常有這樣的要求:
1. 用戶一般只能查看自己部門的數據
2. 可以設置用戶可以查看哪些部門的數據
這種權限的控制,一般稱為數據權限,與之對應的功能權限,則是系統中哪些功能可以使用——①菜單、按鈕等元素能正常顯示;②如果用戶訪問了本身不可見的功能,系統也能阻止(訪問控制)。

開發時間長了,就發現編程一般就是兩個問題:
1. 在哪里設置(數據從哪里來)
2. 在哪里使用(數據到哪里去)
比如工作流引擎,設置,即在界面上拖畫流程圖,並保存為特定的xml數據;使用,即流程引擎解讀xml數據,使其正確的按照用戶的意圖執行程序。
數據權限的問題,同樣可以分成這兩個問題來處理。

設置的問題:
在用戶設置界面,設置用戶的管轄權限

image

做到這樣的設置界面,並不困難。

在這里,主要要解決的一個問題是,如何把這種關系存儲下來
常規方案:使用關聯表[用戶ID,組織ID]
可是發現,一旦組織機構數量多了以后(如省市縣鄉,一般一個省就有1000個鄉/街道以上),再加上用戶數量多了以后——往往是組織機構節點越多,則用戶也越多。理論上,這個關聯表的數據量將到達千萬級(僅理論上,因為對於絕大多數用戶來說,僅能訪問本部門數據)。

創新方案:組織機構使用code做主鍵,並且在用戶表中新建字段為“已授權的組織(authorized_orgs)”,直接使用字符串逗號分隔的方式將該關系存起來。
可是馬上會發現,這個字段會很長很長,一個4級的組織,一般需要8位長的代碼,如果選中的全部數據,按1000個單位來算,就會有9000長度(含逗號)的字符串。
這里有一個取巧的辦法,對於全選了數據,只保存上級單位的code,下級單位就不保存了——因為選中了上級就必然下級全部選上了。

該辦法要求上下級代碼存在一種明顯的關系,如上級代碼為 0100,下級代碼0101。
這個取巧的辦法,理論上依然不能規避很長的組織機構代碼(如選的全部是葉子節點數據),但在實踐中,卻是很好的辦法——應該很少出現全部只選葉子節點,而不選父級節點的。
使用zTree(js的樹)的代碼,可以這樣寫

if(zTree==null){ 
         return; 
     } 
     var nodes = zTree.getNodes(); 
     var arr = []; 
     for(var i=0; i<nodes.length; i++){ 
         pushToArray(arr, nodes[i]); 
     } 
     console.log(arr.join(",")); 
     obj.authorizedOrgs = arr.join(","); 

function pushToArray(arr, node){ 
    if(!node.checked){ 
        return; 
    } 
    if(node.check_Child_State==2||node.check_Child_State==-1){//是節點完全選上(即不是半選狀態)或葉子節點,直接添加 
        arr.push(node.code); 
    }else if(node.check_Child_State==1){//節點半選狀態,遞歸往下找完全選中狀態的 
        for(var i=0; i<node.children.length; i++){ 
            pushToArray(arr, node.children[i]); 
        }    
    } 
}

-----分割線:以上解決怎么設置的問題,以下討論怎么解決使用的問題--------

數據權限控制的基本思路,一般是會執行的SQL語句中添加where條件,以便限定查出的數據,
如 where 所屬機構 in (用戶可訪問的機構)
而不是在數據查詢出來之后,再到代碼中進行過濾——因為一般都會對數據進行高效分頁,如果已經查詢出來數據,再在代碼中進行過濾的話,就可能出現一頁數據不足一頁的情況,數據總數也會與實際頁面上查出的數據行不一致。

第一步,在需要進行過濾的表中,要添加一個字段,如org_code,標明每條記錄所屬的組織機構。
第二步,在查詢語句中加入過濾條件。
我們要加入的SQL語句,大概如下:
where 所屬機構 in ('ZZ0101', 'ZZ0102',...)
假如我們前面存的代碼是'ZZ0100,ZZ0201',其中存的是其父級節點'ZZ0100',代表了 'ZZ0101', 'ZZ0102', ...
所以要寫成
where ((所屬機構 like 'ZZ01%') or (所屬機構='ZZ0201'))
拼湊這樣的SQL語句估計也是比較麻煩的一件事,有沒有簡便一點的方法呢?答案是有。
經查,oracle,sqlserver,mysql都是支持正則式查詢的。
這樣,我們可以把'ZZ0100,ZZ0201'變成一個正則式,放入條件中進行查詢即可!
變成正則式就是 '(^ZZ01.*)|(^ZZ0201)',在mysql使用正則式查詢,就是 where 所屬機構 RLIKE '(^ZZ01.*)|(^ZZ0201)'
變成正則式之后,也便於放入session中進行存儲。
什么,你的數據庫支持正則式,orm不支持正則式,那還用orm做什么?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM