資料權限總的目的:限制某些Role通路某些資料行,比如限制客戶經理Role隻能通路區域是北京的客戶資料,區域是上海的客戶資料,該Role就不能通路。
一般場景:
普通員工可以對自己建立的業務對象有權限,而上級對所有下級建立的業務對象有權限
員工A對區域A的業務對象有權限,員工B對區域B的業務對象有權限
上司A可以看所有銷售紀錄,而大上司隻關心金額超過1000K的銷售紀錄
由于目前OEA對組織結構隻是簡單的支援,是以還不支援上下級等組織關系引起的資料權限,而先隻考慮業務層面帶來的資料權限,如上面的2、3
下圖為項目中一個具體案例,以下一個項目資訊圖,Project為項目,ProjectPBS為項目的一個計量次元,它關聯到PBS。ProjectPBS下有一些屬性值(ProjectPBSPropertyValue),每個屬性值關聯到之前定義的屬性(PBSProperty)。
以下為系統的一個查詢界面,它左邊導航查詢面闆中用到了項目資訊。現在需要控制,下面第二張圖中的項目下拉資料需要考慮權限,選擇項目後PBS顯示也需要考慮權限,也就是說<b>擷取的清單資料必須根據權限過濾過。</b>
根據需求,目前隻支援對象集合的資料權限過濾,資料權限可能出現以下幾個場景:
<b>對象級别</b>
根據本對象的屬性來過濾:如PBS名稱,則在PBS對象設定資料權限表達式 this.Name = "建安工程"
根據子對象的屬性來過濾:如項目PBS屬性值(ProjectPBSPropertyValue)的某個屬性(總建築面積)的輸入值>10000,則在ProjectPB對象設定資料權限表達式 this.ProjectPBSPropertyValues[Name="總建築面積"].Value>10000
根據關聯對象的屬性來過濾:類似2
考慮相關對象(子對象或者關聯對象本身)設定的資料權限,如項目PBS得到的PBS清單考慮PBS本身的資料權限設定
<b>屬性級别</b>
對某個屬性不能檢視
屬性值控制:如金額>10000時不能檢視等
<b>權限控制類型</b>
可讀
可寫
自定義
<b> 目前隻支援對象級别</b>,OEA的對象級别的權限是通過控制清單的形式來展現,目前支援前三種,<b>隻考慮對象本身設定的資料權限,</b>權限控制類型暫考慮<b>可讀</b>
目前實作資料權限基本上有以下方法:
通過動态生成SQL來解決,但這隻能處理簡單的權限設定
通過對每個業務單獨設計來解決,資料庫增加相應表,但這會帶來複雜性,不好統一管理
OEA主要考慮<b>通過表達式來設定對象清單資料權限範圍</b>,一般的資料權限設定可以通過内置的表達式來設定,對于複雜的,和業務相關的,可以通過外部擴充表達式函數,由<b>表達式引擎來解析</b>,這樣就可以處理複雜性,又能做到較好的統一管理。
對于複雜應用時,代碼必須能夠控制擷取的資料是按照權限還是忽略權限,是以必須支援代碼級别上的權限控制,也就是說需要<b>寫代碼來控制</b>,對于通用方法,可以通過代碼生成器來生成。
由于資料權限設定後,需要在代碼中進行相應修改,添加資料檢查步驟,是以配置子產品需要知道系統哪些對象運作設定資料權限。通過給業務對象的則DefaultObject增加InDataPermission屬性來辨別對象支援資料權限功能。
[DefaultObject("5D22DEBC-6EA7-45CD-8245-3D9855AE02A6", Catalog = "名額管理",
InDataPermission=true), Label("項目資訊")]
public partial class Project : GBusinessBase<Project>
修改前
private void DataPortal_Fetch()
{
IsReadOnly = false;
RaiseListChangedEvents = false;
using (var db = Helper.CreateDb())
IQuery q = db.Query();
var list = db.Select<Project>(q);
foreach (var item in list)
this.Add(Project.GetLazy(item.Id));
}
RaiseListChangedEvents = true;
修改後:增加檢查資料權限設定表達式步驟,這部分代碼以後也可以通過代碼生成器來生成
[DataPermission]
if (list.Count == 0) return;
//考慮資料權限時,添加清單前需要執行資料權限表達式
DataPermissionExprParser oe = new DataPermissionExprParser(list[0]);
Project obj = Project.GetLazy(item.Id);
if (oe.CanRead(obj))
this.Add(obj);
注意:由于支援資料權限的業務對象會進行檢查資料步驟,是以對系統性能造成一定影響,是以不需要細粒度控制到行級别資料權限的對象就不要進行資料權限部分的修改
在代碼中隻需要根據業務對象執行個體生成一個表達式引擎 <b>DataPermissionExprParser</b>,它會根據類型以及目前使用者所在的角色來組合設定的目前對象的資料權限表達式,
public class DataPermissionExprParser : ObjectExprParser
string mergedExpr;
public DataPermissionExprParser(object owner)
: base(owner)
Guid businessObjectId = new Guid(owner.GetType().GetSingleAttribute<BusinessObjectAttribute>().Id);
string[] exprs = (Csla.ApplicationContext.User.Identity as OEAIdentity).
GetDataPermissionExpr(businessObjectId);
if (exprs.Length == 0)
mergedExpr = String.Empty;
else if (exprs.Length == 1)
mergedExpr = exprs[0];
else
mergedExpr = string.Join(") OR (", exprs);
mergedExpr = String.Format("({0})", mergedExpr);
if (String.Empty != mergedExpr)
Compile(mergedExpr);
public bool CanRead(object owner)
return String.IsNullOrEmpty(mergedExpr) || (bool)Evaluate(owner);
由于目前項目中隻需要應用到上面一個場景,由于時間關系,是以不可能全部支援,以下為主要的幾個待做清單:
支援資料權限的其它場景(關聯對象級别、屬性級别)
表達式編輯器智能提示
支援自定義表達式編輯器
對于資料量大并且性能要求高,并且可以通過SQL where方式來過濾的情況下,支援where表達式,構造SQL
本文轉自 jingen_zhou 51CTO部落格,原文連結:http://blog.51cto.com/zhoujg/518653,如需轉載請自行聯系原作者