程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 基於EntityFramework的權限的配置和驗證

基於EntityFramework的權限的配置和驗證

編輯:關於.NET

1.   概要

本文主要介紹公司現有系統框架的權限體系,和一些待擴展功能的說明。目前該權限體系基於角色構建(RBAC),原則上,系統中不允許出現對用戶、組織等其他對象指派權限的情況。

 

2.   權限分類

目前系統中的所有表現形式的權限可以歸為兩類:

一類是描述對象或動作是否可見,我們稱之為功能權限(Authority)。例如,菜單的可見性、用戶添加按鈕是否可見、用戶添加方法是否可用等;

另一類是描述可見對象的范圍或動作的影響范圍,我們稱之為數據權限(Permission)。例如,未成年用戶列表、行政區域內數據操作限制等。

說明,這裡authority和permission並不是取英文原意,只是用於程序簡化權限對象命名,實際對應的應該是Function Permission 和 Data Permission。

2.1. 功能權限

功能權限的定義通常都可以序列化存入數據庫。因此,在設計數據庫表時,它和用戶、角色的關系是這樣的:

 

權限和角色、角色和用戶都是多對多的關系,需要建立中間表來存儲。

2.2. 數據權限

數據權限的定義大多數情況下難以序列化存入數據庫。因此,在設計數據庫表時,只需要記錄它和角色的關系即可:

 

3.   實現過程

從用戶的角度來說,他們只關心系統配置好之後是否符合實際業務邏輯,少數用戶會主動參與到配置過程。

3.1. 配置

配置主要做了兩件事情,一是定義權限,二是授權。

功能權限和數據權限的授權並沒有什麼區別,從數據表來看,可以簡單的理解為對Role2Authority和Role2Permission表的數據改動;從界面上來看,如圖

 

菜單權限是功能權限的一種表現形式。

 

3.1.1.   功能權限的定義

而定義則有較大的不同,功能權限可以在沒有確定管理對象的情況進行定義,而且從實際的情況來看,系統的功能或界面設定並不完全和系統管理對象一一對應,功能權限更多的情況是對系統需求的描述。

例如,我們計劃在系統中增加工程對象管理功能,這時可以快速在Authorities表中加入一個菜單權限,用於控制用戶是否可以訪問工程對象管理頁面project.html,而此時,project.html頁面可能還未開發完成,但並不影響權限的定義。另一方面,該權限定義的動作中涉及的對象可能不止工程對象,而是由多個對象操作結合完成的操作;因此,功能權限的定義應該盡量按照用戶需求最小單元來劃分。

 

3.1.2.   數據權限的定義

動態定義

數據權限的定義,目前只實現了預定義,即編碼階段的定義。數據權限授權界面所看到的可選項均為編碼預設的內容。

如果想要在運行時,動態定義數據權限,例如,項目權限中的部門項目,它的定義內容為當前登錄用戶可以查看本部門的項目,這是對項目對象的一個范圍限制。使用SQL語句,可以描述為

SELECT * FROM Projects WHERE OrgId=(SELECT OrgId FROM Users WHERE Id=@UserId)

這裡可以在數據庫中建立一個Permissions表,將上面這條SQL語句的條件部分命名為部門項目,並給定編號3002,存入表中;然後建立Permissions表和Role2Permissions表的外鍵關系實現數據權限的動態配置化,但具體操作下來,會發現很多問題。

首先,聯表查詢時,條件語法是有變化的;其次,動態配置需要有配置界面,在界面上錄入SQL語句是不安全的,而且用戶很可能並不了解SQL語法;在一些管理權限框架中,也有使用條件表達式生成器簡化定義過程,這是可以嘗試的方向。

而本文描述的系統中,數據層采用的是EntityFramework框架,因此無法使用SQL語法來實現動態定義數據權限。或許在對lambda表達式有了足夠了解後,可以嘗試通過文本建立lambda表達式,從而實現動態定義數據權限。

預定義

對於部門項目權限系統采用的是lambda描述

Formula = oper => (pro => pro.Organizations.Contains(oper.Organization));

其中oper為用戶參數,pro為項目參數。數據權限的預定義內容存放在類中,並為此建立新的類庫項目,稱為權限庫。當系統需要新的數據權限時,可以只修改權限庫,生成部署文件,替換運行時環境中的部分文件達到數據權限配置化的目的。

上述表達式Formula只是數據權限對象的一個屬性。數據權限名稱可以定義為部門項目,編號為3002,這樣可以和Role2Permissions表中的PermissionId對應起來,實現對角色的授權。

 

3.2. 驗證

3.2.1.   功能權限的驗證

對於本文描述的B/S系統,功能權限的驗證可分為服務端和客戶端兩個不同實現。

首先,服務端的實現需要攔截所有請求,並根據會話中用戶的角色、請求的資源,逐一匹配權限定義規則,實現驗證。

例如,所有Handler接口都繼承自一個父類,並在父類中進行驗證。

客戶端的實現則是隱藏用戶沒有權限的菜單或按鈕。對於使用後台腳本語言的頁面,可以使用用戶角色下的權限集合很方便的進行控制;而純html前段,則可以考慮首先隱藏所有涉及權限的元素,再通過ajax獲取權限集合,顯示可以訪問的元素。

需要注意的是,服務端驗證是必須要實現,以保證權限系統的可靠性。

3.2.2.   數據權限的驗證

與功能權限不同的是,數據權限主要是對數據范圍的控制;因此,驗證過程最終會在系統數據層實現。這裡有兩種實現方式:一是只讀驗證,另一種是讀寫驗證,各自有優缺點。

只讀驗證的方式如下面這個方法:

 

這是一個API查詢方法,其中condition、verCondtion、attCondition是針對三個對象的數據權限,通過這個查詢方法,用戶將只能得到他可以查看的Project對象及子對象數據。

類似的,分頁查詢、視圖查詢等查詢方法,除了用戶輸入的條件,還需加入PermissionManager提供的數據權限條件,最終交給業務層查詢。這種方式的缺點在於,用戶可能使用查詢權限以外的數據,偽造修改和刪除操作。

讀寫驗證除了查詢方法需要添加額外權限條件,修改和刪除也要先進行數據可讀性查詢驗證。因此,相對而言,讀寫驗證的安全性是最高的,但性能則要比只讀查詢差很多。

3.2.3.   一些細節

條件的合並,PredicateBuilder是專門用於lambda條件表達式合並的工具。通常數據權限條件和用戶查詢條件應該使用And操作。

集中管理數據權限的驗證,上述在API方法中使用PermissionManager獲取數據權限條件的方式是有一些缺點的,例如,這要求所有編碼人員都了解權限驗證的過程,也有遺漏的可能導致數據操作不受控制。對於使用EF框架的系統,可以考慮在DbContext中集成權限驗證過程。

具體的驗證過程,創建一個通用的驗證方法,使用當前用戶作為參數,返回相關對象的過濾條件。由於數據權限是建立在對象基礎上的,因此該驗證方法最好使用泛型。方法將分析用戶的所有角色,以及每個角色下的數據權限授權編號,並根據授權編號從預定義庫中取出所有相關lambda表達進行Or或者And組合。組合方式取決於多角色權限重合的處理策略。

4.   遺留問題

最後,本文雖然到此,但基於EF框架的權限開發還有一些問題尚未解決。例如,動態定義數據權限,權限讀寫驗證的效率問題,數據權限的集中驗證等,希望自己有時間繼續完善。

本文在何問起發布,轉載請注明出處。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved