第四章
细粒度数据查询权限
(上)
通过基于角色访问控制,我们可以控制哪些人具有某种权限。比如总公司员工柴其贵、分公司员工李朵朵和营业部员工贾志宏,三个人都具有访问“查询员工”页面权限。
但,由于他们三人所在公司级别不同(总公司、分公司和营业部),进入查询员工页面,系统展示出来的员工数据应该是不同的。
此类数据查询权限,在业务系统里面随处可见。毕竟
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
细粒度权限管理 阅读(2353)
评论(2) 编辑 收藏