通用權限管理設計 之 數據權限


前言

 

前一篇文章《通用權限管理設計 之 數據庫設計方案》介紹了【主體】- 【領域】 - 【權限】( who、what、how問題原型 ) 的設計思想

 

本文將對這種設計思想作進一步的擴展,介紹數據權限的設計方案。

權限控制可以理解,分為這幾種 :

【功能權限】:能做什么的問題,如增加產品。
【數據權限】:能看到哪些數據的問題,如查看本人的所有訂單。
【字段權限】:能看到哪些信息的問題,如供應商賬戶,看不到角色、 部門等信息。

上面提到的那種設計就是【功能權限】,這種設計有一定的局限性,對於主體,只能明確地指定。對於不明確的,在這里可能就沒辦法處理。比如下面這幾種情況:

數據僅當前部門及上級可見
數據僅當前用戶(本人)可見

類似這樣的就需要用到上面提的數據權限。

上一篇文章我用一個表五個字段完成了【功能權限】的設計思路
本文我將介紹如何利用一個表兩個字段完成這個【數據權限】的設計思路

初步分析

【數據權限】是在【功能權限】的基礎上面進一步的擴展,比如可以查看訂單屬於【功能權限】的范圍,但是可以查看哪些訂單就是【數據權限】的工作了。

在設計中,我們規定好如果沒有設置了數據權限規則,那么視為允許查看全部的數據。

幾個概念
【資源】:數據權限的控制對象,業務系統中的各種資源。比如訂單單據、銷售單等。屬於上面提到的【領域】中的一種
【主體】:用戶、部門、角色等。
【條件規則】:用於檢索數據的條件定義
【數據規則】:用於【數據權限】的條件規則 

 
應用場景
1,訂單,可以由本人查看 
2,銷售單,可以由本人或上級領導查看 
3,銷售單,銷售人員可以查看自己的,銷售經理只查看 銷售金額大於100,000的。

我們能想到直接的方法,在訪問數據的入口加入SQL Where條件來實現,組織sql語句:

1where UserID = {CurrentUserID}
2where UserID = {CurrentUserID} or {CurrentUserID} in (領導)
3where UserID = {CurrentUserID} or ({CurrentUserID} in (銷售經理) and 銷售金額 > 100000)

這些一個一個的"條件",本文簡單理解為一個【數據規則】,通常會與原來我們前台的業務過濾條件合並再檢索出數據。

這是一種最直接的實現方式,在【資源】上面加一個【數據規則】(比如上面的三點)。這樣設計就是

  【資源】 - 【數據規則】

我又覺得不同的人應該對應不同的規則,那么也可以理解為,一個用戶對應不同的角色,每一個角色有不一樣的【數據規則】,那么設計就變成

  【資源】 - 【主體】 - 【數據規則】

根據提供者的不同,准備不同的權限應對策略。

這里可以簡單地介紹一下,這個方案至少需要2張表,一個是  【資源,主體,規則關系表】、一個是【數據規則表】

關系表不能直接保存角色,因為你不確定什么時候業務需要按照【部門】或者【分公司】來定義數據規則

於是可以用  Master、MasterKey  類似這樣的兩個字段來確定一個【主體】

用XML方式的話是這樣配置的(放在數據庫也類似):

<?xml version="1.0" encoding="utf-8"?>
<settings>
<rule view="訂單" role="銷售人員">
銷售員 = {CurrentUserID}
</rule>
<rule view="訂單" role="總銷售經理">
銷售金額 > 100000
</rule>
<rule view="訂單" role="區域銷售經理">
銷售金額 > 100000 and 區域 = {當前用戶所屬區域}
</rule>
</settings>

對於這種方式有興趣的朋友也可以試一下,兩種方式的【數據規則】是一樣的,但是本文沒有采用第二種設計方式,因為它多了一層處理邏輯,我以為應該設計越簡單越好,就采用第一種方式:

  【資源】 - 【數據規則】

當然,上面是用SQL的方式來確定條件規則的,我們當然不會這么做。SQL雖然靈活,但是我們很難去維護,也不知道SQL在我們的界面UI上面如何體現。難不成直接用一個文本框來顯示。這樣對應一個開發人員來說不是問題,可是對應系統管理員,很容易出問題。所以我們需要有另一方式來確定這一規則,並最終可以轉換成我們的SQL語句。

我們的設計關鍵在於如何規范好這些【數據規則】 ,這個規則必須是對前端友好的,而且是對后台友好的,JSON顯然是很好的方式。

 規則說明:

1,數據權限規則總是:{屬性 條件 允許值}

2,數據權限規則可以合並。比如 ( {當前用戶 屬於 銷售人員} and {訂單銷售員 等於  當前用戶} )   Or {當前用戶  屬於 銷售經理}

3,最終我們會用JSON格式

在檢索數據時會先判斷有沒有注冊了某某【資源】的【條件規則】,如果有,那么加載這個【條件規則】並合並到我們前台的【搜索條件】(你的業務界面應該有一個搜索框吧)

 如下圖定義了客戶信息的搜索框,我們搜索客戶ID包括AN,我們組織成的規則將會是:

{"rules":[{"field":"CustomerID","op":"like","value":"AN","type":"string"}],"op":"and"}

為了更好地理解【數據規則】,這里介紹一下【通用查詢機制】 

【通用查詢機制】

權限控制總離不開一些條件的限制(比如查看當前部門的單據),如果沒有完善的通用查詢規則機制,那么在做權限條件過濾的時候你會覺得很別扭。這里介紹一個通用查詢方案,然后再介紹如何實現【數據規則】。

 

早些時候我寫過一篇關於ligerGrid結合.net設計通用處理類的文章《 jQuery liger ui ligerGrid 打造通用的分頁排序查詢表格(提供下載) 》。里面提到的過濾信息是直接的SQL語句。這是不可靠,而且不安全的。
在前端傳輸給后台的過濾信息不應該是直接的SQL,而應該是一組過濾規則。在ligerui V1.1.8 已經加入了一個條件過濾器插件,這個插件組成的規則數據才是我受推薦的:
比如如下

 

{"rules":
[
{"field":"OrderDate","op":"less","value":"2012-01-01"},
{"field":"CustomerID","op":"equal","value":"VINET"}
]
,"op":"and"}

 

規則描述:
查找顧客VINET所有訂單時間小於2011-01-01的單據


這樣的數據是安全的,而且是通用的(你甚至可以再加一個OR子查詢)。無論是在前端還是后台,無論你使用什么樣的組件,都可以很好地利用。

通用后台的翻譯,就可以生成這樣SQL的參數:

 

Text:
([OrderDate] < @p1 and [CustomerID] = @p2)
Parameters:
p1:2012-01-01
p2:VINET

 

下面來點復雜的:查找 顧客VINET或者TOMSP,所有訂單時間小於2011-01-01的單據

 

{
"rules":[{"field":"OrderDate","op":"less","value":"2012-01-01"}],
"groups":[
{"rules":[{"field":"CustomerID","op":"equal","value":"VINET"}, {"field":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}
],
"op":"and"
}

 翻譯結果:

 

Text:([OrderDate] < @p1 and ([CustomerID] = @p2 or [CustomerID] = @p3))
Parameters:
p1:2012-01-01
p2:VINET
p3:TOMSP

 

這個過濾規則分為三個部分:【分組】、【規則】(字段、值、操作符)、【操作符】(and or),而自身就是一個分組。
這種簡單的結構就可以滿足全部的情況。

當然,上面提到的這些條件都是在前台定義(可能是用戶在搜索框自己輸入的)的,而在后台,我們可能會定義一下【隱藏條件】,比如說 【員工只能查看自己的】,要怎么做呢,其實很簡單,只需要在后台接收到這個過濾條件(前台toJSON,后台解析JSON)以后,再加上一個過濾規則(隱藏條件):

 

{field:'EmployeeID',op:'equal',value:5}

 

可以將原來的過濾規則當做一個分組加入進行:

 

 

{op:'and',groups:[

 

{"rules":[{"field":"OrderDate","op":"less","value":"2012-01-01"}],
"groups":[
{"rules":[{"field":"CustomerID","op":"equal","value":"VINET"},{"field":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}
],"op":"and"}

 

],rules:[{field:'EmployeeID',op:'equal',value:5}]
}


 

翻譯如下:

 

Text:
([EmployeeID] = @p1 and ([OrderDate] < @p2 and ([CustomerID] = @p3 or [CustomerID] = @p4)))
Parameters:
p1:5
p2:2012-01-01
p3:VINET
p4:TOMSP



 這樣的【條件規則】才是我們想要的,不僅在前端可以很好地解析,也可以在后台進行處理。在后台我們會定義跟這種數據結構對應的類,那么再定義一個翻譯成SQL的類:


數據權限規則

說了這些,可以開始介紹如何實現【數據規則】了:

上面提到的【隱藏條件】,就是我介紹的【數據規則】
試想一些,這樣 前台的過濾規則,再加上我們之間定義好的 【數據權限】控制 過濾條件。不就達到目的了嗎。
先看看我們在數據庫里保存的這些【數據規則】:

 看不明白?那來個清楚一點的:

規則描述

訂單:【訂單管理員和演示角色可以查看所有的】,【訂單查看員】只能查看自己的

產品:【基礎信息錄入員和演示角色可以查看所有的】,【供應商】只能查看自己的

{CurrentEmployeeID}表示當前的員工。

實質上,我們還可以根據當前用戶信息定義需要的參數,比如:

{CurrentUserID} 當前用戶Id ,對應表【CF_User】

{CurrentRoleID} 當前角色Id ,對應表 【CF_Role】 

{CurrentDeptID} 當前用戶部門Id,對應表【CF_Department】

{CurrentEmployeeID} 當前用戶員工Id,對應表【Employees】(CF_User.EmployeeID)

{CurrentSupplierID} 當前用戶供應商Id,對應表【Suppliers】(CF_User.SupplierID)

 在數據庫中我們直接保存這些用戶參數,在“翻譯”規則成為SQL時,會替換掉:

比如查看訂單,我們得到的SQL,可能是這樣的:

Text:     SELECT * FROM (SELECT TOP 20 * FROM (SELECT TOP 40 * FROM [Orders] WHERE ( 1=1  and ((@p1 in (@p2,@p3)) or (@p4 = @p5 and [EmployeeID] = @p6))) ORDER BY OrderID ASC) AS tmptableinner ORDER BY OrderID DESC) AS tmptableouter ORDER BY OrderID ASC     
Parameters:
@p1[Int32] = 7
@p2[Int32] = 2
@p3[Int32] = 6
@p4[Int32] = 7
@p5[Int32] = 7
@p6[Int32] = 1

{CurrentRuleID} 替換為 7

{CurrentEmployeeID} 替換為1

 下圖是我們設計【數據權限】的界面,可以選擇所有的字段,包括幾個用戶信息:

這些字段不僅僅只是在文本框中輸入值,那么可以自定義數據來源:

 

var fieldEditors = {};
fieldEditors['Orders'] = {
'ShipCity': { type: 'combobox',
options: {
width: 200,
url: "../handler/select.ashx?view=Orders&idfield=ShipCity&textfield=ShipCity&distinct=true"
}
}
};

效果界面:

 


實際應用

既然是數據權限控制,如果有一個統一的數據接收入口,我們倒是可以利用這個入口做一些工作。

比如【ligerRM權限管理系統】統一使用 grid.ashx 這個數據處理程序作為列表數據的接收入口。

有了統一的接口,方便做權限的控制,使用過 ligerGrid Javascript表格,或者類似插件的朋友,應該比較清楚服務器的交互原理。
在grid.ashx中,我們會通過
【視圖/表名 】、 【排序信息】、【分頁信息】、【過濾信息】
這幾個指標來獲取指定的數據。


而在實際的業務中,可能會引入權限的控制。比如某某【資源】,只能由當前用戶自身才能查看,或者只能由當前用戶部門及上級部門才能查看。對於這些控制,我們采用對這些可能做權限控制的【資源】注冊一組【條件規則】的方式來進行。

 我們將找到view定義好的【數據權限規則】,然后和用戶在前台搜索框輸入的【搜索規則】合並:

上面的代碼就是數據條件合並的例子,這樣便得到了我們最終需要的 過濾規則。

結語

本文提出了數據權限的一種實現思路,只是本人在做一個web應用時構思的方案,談不上規范,歡迎提出你的建議意見。

可以在http://case.ligerui.com體驗實際的應用效果。


免責聲明!

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



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