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

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

開發時間長了,就發現編程通常就是兩個問題:
1. 在哪裏設置(數據從哪裏來)
2. 在哪裏使用(數據到哪裏去)
好比工做流引擎,設置,即在界面上拖畫流程圖,並保存爲特定的xml數據;使用,即流程引擎解讀xml數據,使其正確的按照用戶的意圖執行程序。
數據權限的問題,一樣能夠分紅這兩個問題來處理。 mysql

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

image

作到這樣的設置界面,並不困難。 數據庫

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

創新方案:組織機構使用code作主鍵,而且在用戶表中新建字段爲「已受權的組織(authorized_orgs)」,直接使用字符串逗號分隔的方式將該關係存起來。
但是立刻會發現,這個字段會很長很長,一個4級的組織,通常須要8位長的代碼,若是選中的所有數據,按1000個單位來算,就會有9000長度(含逗號)的字符串。
這裏有一個取巧的辦法,對於全選了數據,只保存上級單位的code,下級單位就不保存了——由於選中了上級就必然下級所有選上了。 session

該辦法要求上下級代碼存在一種明顯的關係,如上級代碼爲 0100,下級代碼0101。
這個取巧的辦法,理論上依然不能規避很長的組織機構代碼(如選的所有是葉子節點數據),但在實踐中,倒是很好的辦法——應該不多出現所有隻選葉子節點,而不選父級節點的。
使用zTree(js的樹)的代碼,能夠這樣寫 oracle

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]); 
        }    
    } 
}

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

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

第一步,在須要進行過濾的表中,要添加一個字段,如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作什麼?code

相關文章
相關標籤/搜索