JiveJdon Community Forums
在线209人 J道首页 | 论坛首页 | 培训咨询 | 开源框架 | 精华 | 查搜 | 注册 | 登陆 |
首页 » 论坛 » 项目工程开发经验谈
???en_US.forumThreadPrev.name??? 上一主题
Go back to the topic listing   返回主题列表
???en_US.forumThreadNext.name??? 下一主题
这个主题共有 23 回复 / 2 页 [ 1 2 下一页 ]  发表新帖子  回复该主题贴
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
在jsp web项目中实现透明的权限控制 发表: 2003年09月24日 11:12 回复
现在想到的是在Filter中做……

目标:通过配置来实现权限管理,在业务代码中无需再考虑权限问题
参考:类似tomcat的realm,在进到项目前,已经由容器判断了权限。权限管理通过配置来实现,在业务代码中无需再考虑权限问题。不足是,servlet规范中用URL Pattern配置访问级别,不够灵活
办法:在Filter中做权限判断?
我做了一个接口
boolean isUserHasPerm(String user, String url)

MyFilter调用接口

if (!isUserHasPerm(...))
response.sendError(403, "Forbidden");

isUserHasPerm接口已经初步实现,???现在的问题是Filter好像不是放权限判断的地方???,因为签名是这样的:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)

其中request 是ServletRequest, 不是HttpServletRequest,
response是ServletResponse,不是HttpServletResponse
这样就没有request.getSession().getAttribute("userinfo"),//得到权限判断的who要素
没有response.sendError() //这样没有权限,该如何处理?
???当然可以强行转换,tomcat下也不会cast错误,但始终不是个办法……???

-----------------------------------------------
另外,说明一下isUserHasPerm的实现
相关联的对象图


核心是ACL表,实际操作给出role,function,resource三要素,如果ACL表中有记录,说明可以访问,因为三要素唯一确定一条ACL记录(function通过resoure type和operate type确定)

优化后,剩三个表,User,Role,ACL(当然,因为User,Role是多对多,还要一个关联表)
ACL表包含四个字段:
Role, Component, Instance, OP(参考了PostNuke的权限设置)

Component就是resource type,
Instance就是resource
OP就是function

合并进Component和OP,而不是functionID的好处是,可以通过通配符来设置权限,比如设置一个全局的管理权限,只需要一条记录

role=admins, component=*, instance=*, OP=*

另外,OP字段还可以等于DENY,有优先权,如果找到一条匹配的DENY记录,直接就是没有权限了。有了DENY,如果需要赋大部分权限,排除一小部分,也比较容易配置

isUserHasPerm的伪码

(1)
select * from ACL
where Role in (user.getRoles())
and Component in (url.getComponent, *)
and Instance in (url.getInst, *)
and OP = DENY

(2)
if (结果集>=0)
return false;

(3)
将(1)的OP条件改为
and OP in (url.getOP, *)

(4)
if (结果集>0)
return true;
else
return false;


*注:从url中得到权限判断的要素,当然需要一些规则了,比如
category.do?op=add&id=1
表示component是category
op是add
instance是1
role当然是从session中拿
zingers

发表文章: 178
注册时间: 2002年08月14日 16:11
Re: 在jsp web项目中实现透明的权限控制 发表: 2003年09月24日 15:44 回复
稍微看了一下,如果我的意见和事实不符合请见谅。

我觉得用filter来执行权限判断是不可能的,因为基于数据库应用的URL经常是一致的,只是后面的参数不一样。有些参数还是表单发送的。
所以,用它来执行中文化是不错的,但是来实现ACL功能好象不行,tomcat可以是因为它的各部分是不同的URL吧。

我觉得windows2000的许可和角色和树状继承很不错,不过在应用中实现还是有难度。
banq

发表文章: 8914
注册时间: 2002年08月03日 17:08
Re: 在jsp web项目中实现透明的权限控制 发表: 2003年09月24日 16:31 回复
filter概念实际就是Proxy模式实现。

ACL是肯定要用Proxy模式实现,关键是如何实现比较巧妙,象Jive那样,为每个数据Model建立Proxy(filter)的做法是不可取的,动态Proxy好像是比较好的方法,根据操作方法名称,如果get,表示读取操作,update表示更新,缺点是,要求对EJB或Service操作方法实现统一命名限制。

通过EJB容器的安全机制,在EJB-jar.xml中配置ACL也是目前比较好的办法,缺点是需要管理员修改EJB-jar.xml,那么在此基础上,编制管理程序操作修改EJB-jar.xml可以达到方便ACL设置吧。
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
Re: 在jsp web项目中实现透明的权限控制 发表: 2003年09月25日 09:27 回复
>只是后面的参数不一样。有些参数还是表单发送的。
其实在filter中传入的参数是request,参数可以通过getRequestURI,getParameter来获取,

问题是如何通过request提取出
role,component,instance,op, 这个规则不太好定:
能要求URI就是component?
instance一定要用名为id的parameter来确定?
要显式的给出op参数?

而且,定了这样的规则,方案就不透明了

wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
一、数据库 发表: 2003年09月25日 13:33 回复
下面给出isUserHasPerm的初步实现

一、数据库,mssqlserver

drop table hive_acl;
drop table hive_account_role;
drop table hive_account;
drop table hive_role;

create table hive_account (
id int identity,
account varchar(50) unique not null,
password varchar(16) not null,
primary key (id),
);

create table hive_role (
id int identity,
role varchar(50) unique not null,
primary key (id),
);

create table hive_account_role (
account_id int,
role_id int,
primary key (account_id, role_id),
foreign key (account_id) references hive_account(id),
foreign key (role_id) references hive_role(id),
);

create table hive_acl (
role_id int,
component varchar(50),
instance varchar(50),
op varchar(50),
primary key (role_id, component, instance, op),
foreign key (role_id) references hive_role(id),
);

insert into hive_account (account, password) values ('admin', 'abc');
insert into hive_account (account, password) values ('amen', 'abc');
insert into hive_account (account, password) values ('anonymous', '');

insert into hive_role (role) values ('admins');
insert into hive_role (role) values ('users');
insert into hive_role (role) values ('guests');

insert into hive_account_role (account_id, role_id) values (1,1);
insert into hive_account_role (account_id, role_id) values (1,2);
insert into hive_account_role (account_id, role_id) values (2,2);
insert into hive_account_role (account_id, role_id) values (3,3);

insert into hive_acl (role_id, component, instance, op) values (1, '*', '*', '*');
insert into hive_acl (role_id, component, instance, op) values (2, 'category', 'manager', 'none');
insert into hive_acl (role_id, component, instance, op) values (2, 'category', '*', 'read');
insert into hive_acl (role_id, component, instance, op) values (2, 'category', 'public', 'write');
insert into hive_acl (role_id, component, instance, op) values (3, 'category', 'public', 'read');

wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
二、两个测试的sql语句 发表: 2003年09月25日 13:40 回复
测试权限的核心语句,其实后面的java方法只是另一种实现
1) 查询相应的op=none的记录,如果记录数大于则没有权限
2) 查询匹配记录,如果记录数等于0(没有acl记录)则没有权限

-- 判断是否有op=none的acl记录
declare @account varchar(50);
declare @component varchar(50);
declare @instance varchar(50);
declare @op varchar(50);

select @account = 'anonymous';
select @component = 'category';
select @instance = 'manager';
select @op = 'write';

select * from hive_acl
where role_id in (
select role_id
from hive_account_role inner join hive_account
on hive_account_role.account_id = hive_account.id
where account = @account
)
and component in (@component, '*')
and instance in (@instance, '*')
and op ='none'
;


-- 判断是否有匹配的acl记录
declare @account varchar(50);
declare @component varchar(50);
declare @instance varchar(50);
declare @op varchar(50);

select @account = 'amen';
select @component = 'category';
select @instance = 'manager';
select @op = 'write';

select * from hive_acl
where role_id in (
select role_id
from hive_account_role inner join hive_account
on hive_account_role.account_id = hive_account.id
where account = @account
)
and component in (@component, '*')
and instance in (@instance, '*')
and op in (@op, '*')
;
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
三、PermissionManager接口 发表: 2003年09月25日 13:42 回复
将由filter调用


public interface PermissionManager {

public boolean isUserHasPerm(HttpServletRequest request);

}
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
四、PermissionFilter 发表: 2003年09月25日 13:45 回复


public class PermissionFilter implements Filter {
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {

try {
HttpServletRequest req = (HttpServletRequest)request;
if (!HiveFactory.getDefaultHive().getPermissionManager().isUserHasPerm(req)) {
HttpServletResponse rep = (HttpServletResponse)response;
rep.sendError(403);
}

} catch (Exception e) {
}

try {

filterChain.doFilter(request, response);
} catch (Exception e) {
}
}
}
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
五、PermissionManager的实现 发表: 2003年09月25日 13:47 回复


public class PermissionManagerImpl implements PermissionManager {

public boolean isUserHasPerm(HttpServletRequest request) {
HttpSession session = request.getSession();
Account user = (Account)session.getAttribute("userinfo");
if (user == null)
user =
HiveFactory
.getDefaultHive()
.getUserManager()
.getAnonymousUser();

String component, instance, op;
// get component from URI
{
String uri = request.getRequestURI();
int i, j;
i = uri.lastIndexOf(
"/");
j = uri.indexOf(
".do", i);
component = uri.substring(i+1, j).toLowerCase();
}
// get instance
instance = request.getParameter(
"id");
// get op
op = request.getParameter(
"op");
return isUserHasPerm(user.getAccount(), component, instance, op);
}


private boolean isUserHasPerm(
String account,
String component,
String instance,
String op) {
try {
Connection cn = HiveFactory.getDefaultHive().getConnection();
if (cn == null)
return false;
String sql;
PreparedStatement pstm;
ResultSet rs;
int count;

sql =
"select count(*) from hive_acl"
+
" where role_id in ("
+
" select role_id"
+
" from hive_account_role inner join hive_account"
+
" on hive_account_role.account_id = hive_account.id"
+
" where account = ?"
+
" )"
+
" and component in (?, '*')"
+
" and instance in (?, '*')"
+
" and op ='none'";
pstm = cn.prepareStatement(sql);
pstm.setString(1, account);
pstm.setString(2, component);
pstm.setString(3, instance);
rs = pstm.executeQuery();
rs.next();
count = rs.getInt(1);
if (count >= 1) {
cn.close();
return false;
}

sql =
"select count(*) from hive_acl"
+
" where role_id in ("
+
" select role_id"
+
" from hive_account_role inner join hive_account"
+
" on hive_account_role.account_id = hive_account.id"
+
" where account = ?"
+
" )"
+
" and component in (?, '*')"
+
" and instance in (?, '*')"
+
" and op in (?, '*')";
pstm = cn.prepareStatement(sql);
pstm.setString(1, account);
pstm.setString(2, component);
pstm.setString(3, instance);
pstm.setString(4, op);
rs = pstm.executeQuery();
rs.next();
count = rs.getInt(1);

cn.close();
if (count == 0) {
return false;
}
return true;

} catch (SQLException e) {
e.printStackTrace();
return false;
}
}

}
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
四.(1)、PermissionFilter的设置 发表: 2003年09月25日 13:52 回复
在web.xml中,PermissionFilter设置过滤"/secu/*"的请求


<web-app>
<filter>
<filter-name>permissionfilter</filter-name>
<filter-class>com.stalent.hive.permission.PermissionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>permissionfilter</filter-name>
<url-pattern>/secu/*</url-pattern>
</filter-mapping>
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
六、一些说明 发表: 2003年09月25日 13:58 回复
前面

insert into hive_acl (role_id, component, instance, op) values (1, '*', '*', '*');
insert into hive_acl (role_id, component, instance, op) values (2, 'category', 'manager', 'none');
insert into hive_acl (role_id, component, instance, op) values (2, 'category', '*', 'read');
insert into hive_acl (role_id, component, instance, op) values (2, 'category', 'public', 'write');
insert into hive_acl (role_id, component, instance, op) values (3, 'category', 'public', 'read');

前面insert的数据表示:
假想有一种“category”的资源(可以想象成目录、论坛的板块之类)
有public,manager以及其他的一些实例
role_id=1是admins,2是users,3是guests
admins有所有权限
users可以读除manager外的所有资源,并对public可写
guests只能读public
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
七、测试 发表: 2003年09月25日 14:06 回复
以users登录
/hiveweb/secu/category.do?op=read&id=manager
403 Forbidden

/hiveweb/secu/category.do?op=read&id=public
400 Invalid path

……
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
八、请教如何改进设计 发表: 2003年09月25日 14:24 回复
一、没有owner的概念,比如要让用户对自己创建的资源有编辑权,怎么办?……

二、PermissionFilter,如果设为过滤"/*",又是根目录下的项目,tomcat启动时也会调用doFilter方法,这不是我想要的

三、PermissionFilter中,downcast ServletRequest到HttpServletRequest,会不会有隐患?上传文件通过mutipart form提交的request会不会转换错?还有没有其他不能cast的情况?

四、用资源类型、操作类型能唯一确定一个功能吗?

xangd

发表文章: 1
注册时间: 2003年09月25日 14:22
Re: 在jsp web项目中实现透明的权限控制 发表: 2003年09月25日 14:24 回复
可以参见 seraph
http://opensource.atlassian.com/seraph
wuliang

发表文章: 14
注册时间: 2003年09月24日 09:20
Re: 在jsp web项目中实现透明的权限控制 发表: 2003年09月25日 14:52 回复
Woo~
Seraph is a 'gate keeper' for J2EE applications - thus was named after Seraph from the Matrix Reloaded.

thumbup!;)
这个主题有 23 回复 / 2 页 [ 1 2 下一页 ]
???en_US.forumThreadPrev.name??? 上一主题
Go back to the topic listing   返回主题列表    返回页首  返回页首
???en_US.forumThreadNext.name??? 下一主题
热点TAG: AOP cache DDD EJB 集群 设计模式 Hibernate IOC JiveJdon OO RBAC Spring Struts
查询本论坛内 回复超过的热门帖子
快速发表回复
标题
 
粗体 斜体 下划线 插入图片 插入代码 插入url链接 插入附件
内容
 

解惑之道在J道 ,打造中国最具影响力的的企业软件社区
OpenSource JIVEJDON v3.0 Powered by JdonFramework Code © 2002-07 jdon.com

anti spam