第四章
細粒度數據查詢權限
(上)
通過基于角色訪問控制,我們可以控制哪些人具有某種權限。比如總公司員工柴其貴、分公司員工李朵朵和營業部員工賈志宏,三個人都具有訪問“查詢員工”頁面權限。
但,由于他們三人所在公司級別不同(總公司、分公司和營業部),進入查詢員工頁面,系統展示出來的員工數據應該是不同的。
此類數據查詢權限,在業務系統里面隨處可見。畢竟
N
多操作,都起源于查詢。連增加數據操作都有,比如增加表單的某個下拉框內容,可能來自數據庫查詢。
數據查詢權限,包括
2
個緯度:行級和列級。
現有方案
常見拼湊
SQL
常見做法是,采用
if
else
做判斷,決定執行那條程序分支,也就是
SQL
。
String sql=””;
if( user.getCompanyLevel()==Constants.總公司 ) {
sql=”select * from demouser u, company c where u.companyId=c.id”; //查詢所有員工
} else if( user.getCompanyLevel()==Constants.分公司 ) {
String currentUserCompanyId=user.getCompanyId();
sql=” select * from demouser u, company c where u.companyId=c.id and c.id”= currentUserCompanyId + “ or c.pid=”+currentUserCompanyId; //查詢本分公司及下屬營業部員工
} else if( user.getCompanyLevel()==Constants.營業部 ) {
String currentUserCompanyId=user.getCompanyId();
sql=” select * from demouser u, company c where u.companyId=c.id and c.id”= currentUserCompanyId; //查詢本營業部員工
}
變通方法
也有不少開發者對上述方法做了改進,我了解到如下改進方法:
1. 采用
AOP
技術,向
find/select
模型注入
where
條件;
2. 將
SQL
語句全部提取出來,集中保存在某個
SQL
配置文件里面,類似
HIBERNATE
那樣。
上述方法,都不能減少
if
else
判斷,只是把
SQL
語句做了轉移。
AOP
注入方式,將
if else
判斷從模型層轉移到注入層。集中提取
SQL
方式,只是將
SQL
轉移到統一的保存文件,
if else
依然轉移不掉。
關于列級控制、分頁查詢和自定義條件查詢,那就更麻煩了,在此不做敘述。
如果使用
Metadmin
在設計
Metadmin
之初,我們確定了這些目標:
1. 將行列級授權邏輯、
if else
判斷全部從業務代碼中剝離出去,達到權限與業務完全解開耦合;
2. 提供
API
供業務方法調用,通過該方法獲取該用戶具有權限查詢的數據;
3. 整個過程不要編碼,也不要
XML
,通過界面設計出來,并且每個查詢邏輯設計完畢,可以立即在線測試,保證查詢邏輯無誤。
為此,
Metadmin
提供如下服務:
1. Metadmin
提供數據查詢
API
:告訴
metadmin
,當前是誰想要查什么數據,
metadmin
就能返回該用戶具有權限查詢的數據;
2. Metadmin
提供的
API
支持分頁和自定義條件查詢,當然這一切都是在該用戶的授權范圍內;
3. 權限設計器,通過設計器展現出業務數據庫表,運用鼠標拖拽等操作把查詢邏輯設計出來,并可以在線測試;
4. 支持復雜、特定數據庫邏輯手工輸入
SQL
,調優性能。
以下演示來自
metadmin
下載包里面包含的演示示例,可以在
www.metadmin.com
下載
Metadmin
安裝程序包。
API
MetadminService
類:
static QueryResult
|
query
(int privilegeId, User
user,
java.util.Map context)
評估查詢授權策略,返回查詢結果。
|
static QueryResult
|
query
(int privilegeId, User
user,
java.util.Map context, CustomizedWhere
where)
評估查詢授權策略,返回查詢結果。
|
static QueryResult
|
query
(int privilegeId, User
user,
java.util.Map context, CustomizedWhere
where,
int first, int max)
評估查詢授權策略,返回查詢結果,支持分頁。
|
static QueryResult
|
query
(int privilegeId, User
user,
java.util.Map context, int first, int max)
評估查詢授權策略,返回查詢結果,支持分頁。
|
static int
|
queryCount
(int privilegeId, User
user,
java.util.Map context)
評估查詢授權策略,返回匹配記錄的個數。
|
static int
|
queryCount
(int privilegeId, User
user,
java.util.Map context, CustomizedWhere
where)
評估查詢授權策略,返回匹配記錄的個數。
|
WebMetadminService
類,為
WEB
程序定制的類,從
HttpRequest
自動讀取當前用戶:
static java.util.Collection
|
query
(HttpServletRequest req, int privilegeId)
評估查詢授權策略,返回查詢結果。
|
static java.util.Collection
|
query
(HttpServletRequest req,
int privilegeId, CustomizedWhere
where)
評估查詢授權策略,返回查詢結果,支持分頁。
|
static java.util.Collection
|
query
(HttpServletRequest req,
int privilegeId, CustomizedWhere
where,
int first, int max)
評估查詢授權策略,返回查詢結果,支持分頁。
|
static java.util.Collection
|
query
(HttpServletRequest req, int privilegeId,
int first, int max)
評估查詢授權策略,返回查詢結果,支持分頁。
|
static java.util.Collection
|
query
(HttpServletRequest req, int privilegeId,
java.util.Map context)
評估查詢授權策略,返回查詢結果,支持分頁。
|
static java.util.Collection
|
query
(HttpServletRequest req, int privilegeId,
java.util.Map context,CustomizedWhere
where)
評估查詢授權策略,返回查詢結果。
|
static java.util.Collection
|
query
(HttpServletRequest req, int privilegeId,
java.util.Map context,CustomizedWhere
where,
int first, int max)
評估查詢授權策略,返回查詢結果,支持分頁。
|
static java.util.Collection
|
query
(HttpServletRequest req, int privilegeId,
java.util.Map context, int first, int max)
評估查詢授權策略,返回查詢結果,支持分頁。
|
static int
|
queryCount
(HttpServletRequest req,
int privilegeId)
評估查詢授權策略,返回匹配記錄的個數。
|
static int
|
queryCount
(HttpServletRequest req,
int privilegeId, CustomizedWhere
where)
評估查詢授權策略,返回匹配記錄的個數。
|
static int
|
queryCount
(HttpServletRequest req, int privilegeId,
java.util.Map context)
評估查詢授權策略,返回匹配記錄的個數。
|
static int
|
queryCount
(HttpServletRequest req, int privilegeId,
java.util.Map context,CustomizedWhere
where)
評估查詢授權策略,返回匹配記錄的個數。
|
業務數據庫
第一章講解了
Metadmin
對于數據庫的分類:權限數據和業務數據,兩者保存在不同
schema
里面。
WEB-INF/metadmin/datasources.xml
:
<?xml version="1.0"?>
<datasources>
<datasource name="metadmin" configFile="metadmin.properties"/>
<datasource name="mydemo" configFile="mysql.properties" schemas="mydemo, metadmin"/>
</datasources>
name=”mydemo”
的數據源表示業務數據源,具體配置信息在
mysql.properties
文件里面,打開設計器時,只展示該數據庫的
mydemo
和
metadmin
兩個
schema
數據庫表和視圖。
具體數據源配置信息,參閱:
http://www.metadmin.com/doc/main.html#數據源
2.6
數據查詢設計器
在打開數據查收設計器之前,開發者先準備好
JavaBean
,也就是打開把查詢出來的數據保存到哪個
Java
值對象。演示程序提供了
Employee
,將查詢出來的數據保存到該
JavaBean
里面。
Employee.java
package org.back.demo;
import java.util.Date;
public class Employee {
private int id;
private int companyId;
private int departmentId;
private String loginName;
private String name;
private String password;
private String companyName;
private String departmentName;
private int isManager;
private Date hireDate;
// … get/set methods…
}
啟動
web
服務器,在瀏覽器輸入:
http://localhost:8080/mydemo/metadmin/designer
(假定您發布的
web
context
是
mydemo
,且服務器端口是
8080
)
打開左邊條形框里面的“數據查詢”,在樹上右擊,選擇“新增數據查詢”。如圖示:

在彈出的框里面輸入相關信息,如圖示:

我們先新建總公司用戶查看數據的
SQL
,分公司和營業部用戶查詢
SQL
以及怎樣與業務系統集成,由于篇幅關系,下章講述。
在數據查詢樹上,單擊“查詢所有員工”,系統自動展現數據查詢設計器。
然后按照如下步驟操作:
1. 展開
mydemo schema
,展開表;
2. 雙擊
company, department, demouser
表,因為要查詢這三張表;
3. 勾選
company
表
name
字段,
department
表
name
字段,勾選
demouser
表所有字段;
4. 在映射類里面,輸入
org.back.demo.Employee
;
5. 檢查下面的字段映射是否有誤,修改
company
表的
name
映射屬性為
companyName
,修改
department
表的
name
映射屬性為
departmentName
。
如圖示:

到此,設計還差一個步驟,設置
where
條件。本查詢
where
條件是
3
張表關聯。
按照如下步驟操作:
1. 點擊設計器下方的“
WHERE
”標簽頁
2. 右擊條件組,選擇“新增二元條件”;
3. 點擊第一個字段節點,在右邊選擇“
company.id
”也就是
company
表的
id
字段;
4. 然后,設置第二個字段為“
demouser.companyId
”字段;
5. 右擊條件組,選擇“新增二元條件”;
6.
將第一個字段選擇為“
department.id
”,第二個字段選擇為“
demouser.departmentId
”。
至此,三表關聯完畢。也就是完成
SQL
:
company.id=demouser.companyId and department.id=demouser.departmentId
。
如圖示:

現在,我們可以測試了!選擇設計器下方“測試”標簽頁,點擊控制臺執行小圖標。
Metadmin
將顯示該
sql
語句能查詢的數據,行列級!
如圖示:

至此,我們完全放心該
SQL
語句沒有任何問題。點擊“保存”圖標,保存設計結果。
下章,講解其他
SQL
還有怎樣與業務系統集成。
posted on 2009-06-19 11:52
細粒度權限管理 閱讀(2385)
評論(2) 編輯 收藏