在jsp web项目中实现透明的权限控制

wuliang 03-09-24
    

现在想到的是在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中拿

    

1
zingers
2003-09-24 15:44

稍微看了一下,如果我的意见和事实不符合请见谅。

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

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

banq
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
2003-09-25 09:27

>只是后面的参数不一样。有些参数还是表单发送的。
其实在filter中传入的参数是request,参数可以通过getRequestURI,getParameter来获取,

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

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

wuliang
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');

5Go 1 2 3 4 ... 5 下一页