背景
多數企業應用都需要對數據權限進行控制,如:某個用戶只能看到某個范圍的數據(數據行)、某個用戶只能看到某幾列數據(數據列)。本文以數據行級別的權限控制為范例,談談如何設計權限模型和查詢 API。
權限模型
結合自己的項目需求,可以省略掉“數據角色”,直接讓“用戶”聚合“數據權限”,也可以只保留一個“角色”,讓“角色”聚合“操作權限”和“數據權限”。
可擴展的數據權限模型
偽代碼示例
1 class SessionInfo 2 { 3 public Guid UserId { get; set; } 4 5 public Guid DepartmentId { get; set; } 6 } 7 8 interface IDataPermissionProvider 9 { 10 string CreateSQL(SessionInfo sessionInfo, Dictionary<string, object> args); 11 } 12 13 [DisplayName("我的")] 14 class DepartmentDataPermissionProvider : IDataPermissionProvider 15 { 16 public string CreateSQL(SessionInfo sessionInfo, Dictionary<string, object> args) 17 { 18 return String.Format("( CreateUserId = '{0}' )", sessionInfo.UserId); 19 } 20 } 21 22 [DisplayName("指定部門")] 23 class MySelfDataPermissionProvider : IDataPermissionProvider 24 { 25 public string CreateSQL(SessionInfo sessionInfo, Dictionary<string, object> args) 26 { 27 return String.Format("( DepartmentId = '{0}' )", args["DepartmentId"]); 28 } 29 }
草圖示例
說明
很容易將這部分“插件化”,如支持“自定義”,然后顯示一個輸入框,可以輸入:“Price > 130”。
如何設計查詢API?
先看兩個用例
上面兩個用例,對訂單有兩種查詢需求,我們如何設計這種查詢 API 呢?
- 第一種:
1 class QueryService 2 { 3 public QueryResult Query(UserCase userCase, DynamicQuery query) 4 { 5 // 根據 userCase 決定是否或如何動態的追加數據權限。 6 return null; 7 } 8 }
需要根據不同的 UserCase,決定是否追加數據權限,如:A 用例需要數據權限,B 用例不需要,UserCase 可能是“當前請求的模塊名字”或“當前請求的URL”。
- 第二種:
class QueryService { public QueryResult QueryA(DynamicQuery query) { return null; } public QueryResult QueryB(DynamicQuery query) { return null; } }
我更喜歡這種風格。
上面的 DynamicQuery 並不是“萬能的查詢條件”,而是滿足某一用例的不同查詢組合的一種“規約”,很多系統都提供“萬能查詢”,也算是一種特殊的“規約”了。
另外需要注意的是:一個用例會有多種查詢需求的(或者叫查詢組合)。
備注
倉促成文,有這方面經驗的朋友請留言批評。