论坛首页 Java版 Spring

请问这样的细粒度权限能否用acegi实现?

浏览 26123 次
该帖已经被评为精华帖
作者 正文
时间:2006-01-03
有这样的功能需求:
普通职员能划拨10万以下的资金;
经理能划拨100万以下的资金;
董事长划拨1000万以下的资金;

而且,以后资金的数量大小可以会变动,能修改资金数量值。

也就是说,要达到实例级或字段级的权限,用acegi能否做到呢?或者还是用其它什么方法可以实现呢?

期待中!
   
时间:2006-01-03
jackofnh 写道
有这样的功能需求:
普通职员能划拨10万以下的资金;
经理能划拨100万以下的资金;
董事长划拨1000万以下的资金;

而且,以后资金的数量大小可以会变动,能修改资金数量值。

也就是说,要达到实例级或字段级的权限,用acegi能否做到呢?或者还是用其它什么方法可以实现呢?

期待中!

这个究竟是权限还是业务逻辑
   
0 请登录后投票
时间:2006-01-03
其实,举的那个例子不太恰当,可能令人误解,我的意思是,acegi能否用于实例级或字段级的权限管理。如,对一条发言记录,只有版主和发言者有权删除,其它人只能查看。怎样呢?
   
0 请登录后投票
时间:2006-01-03
你这个问题的需求很像是ACL模型的升级版本。acegi在0.5以后已经加入了这个功能,其实就是多了一种voter。你的这个需求完全可以做到,甚至更复杂的。我先回答到这吧。

最好楼主说说自己的思路,因为acegi的涉及到的东西比较多,一时说不明白。需要楼主先对acegi的ACL实现有一个了解,现在新版本里面有例子可以看看。要是楼主有个思路我尽量帮助你整理一下。

最近正好想在自己的组织里面讲讲acegi,很期望为楼主回答问题,也算是我先热热身。
   
0 请登录后投票
时间:2006-01-03
先回答一下一楼的问题。严格的说,这个不是acl的模型,因为没有细粒度到每一个实例对象,而是基于一定的业务逻辑来将业务对象划分开来。所以说用acegi来实现某种意义上来说是不妥当的,但是为了说明acegi能够做到,特举例如下:


首先我来假设一下业务编码。

MoneyManager 管理钱的业务方法,是不时有点太土了。
MoneyManager.appropriatingFunds(Double money)
拨款的方法。先用double了,按理说应该用XO来替代。

假设你已经配好了acegi的环境,准备对这个方法进行权限管理了。

首先acegi的方法拦截要拦下拨款这个业务方法,这个是一定的。

[code:1]
<bean id="managerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref bean="businessAccessDecisionManager"/></property>
<property name="afterInvocationManager"><ref local="afterInvocationManager"/></property>
<property name="objectDefinitionSource"><value>
[b]yourpackage.MoneyManager.appropriatingFunds=APP_FUNDS[/b]
</value>
</property>
</bean>
[/code:1]

注意这里黑体的地方,这就说明要运行MoneyManager.appropriatingFunds这个方法一定要有投票者支持APP_FUNDS这个属性,还要投出赞成票。

接下来我们来实现我们自己的投票者。
   
0 请登录后投票
时间:2006-01-03
实现投票者就是要实现acegi的AccessDecisionVoter,假设我们自己的投票者是appropriatingFundsVoter。

[code:1]
package com.xxx.voter;

import java.lang.reflect.Method;
import java.util.Iterator;

import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.vote.AccessDecisionVoter;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.StringUtils;

public class AppropriatingFundsVoter implements AccessDecisionVoter {

private final String APP_FUNDS = "APP_FUNDS";

public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null)
&& attribute.getAttribute().equals(APP_FUNDS)) {
return true;
} else {
return false;
}
}

public boolean supports(Class clazz) {
return true;
}

public int vote(Authentication authentication, Object object,
ConfigAttributeDefinition config) {
int result = ACCESS_ABSTAIN;
Iterator iter = config.getConfigAttributes();

while (iter.hasNext()) {
ConfigAttribute attribute = (ConfigAttribute) iter.next();

if (this.supports(attribute)) {
result = ACCESS_DENIED;

MethodInvocation invocation = (MethodInvocation) object;

// Check if this MethodInvocation provides the required argument
Method method = invocation.getMethod();
Class[] params = method.getParameterTypes();
Double money = null;

for (int i = 0; i < params.length; i++) {
if (Double.class.isAssignableFrom(params[i])) {
money = (Double)invocation.getArguments()[i];
}
}

if(money == null)
throw new AccessDeniedException("appfunds.noarg");

// Attempt to find a matching granted authority
for (int i = 0; i < authentication.getAuthorities().length; i++) {
String auth = authentication.getAuthorities()[i].getAuthority();
if (auth.startsWith("ROLE_") && checkMoneyAuth(money, StringUtils.replace(auth, "ROLE_", ""))) {
return ACCESS_GRANTED;
}
}
}
}

return result;
}

private boolean checkMoneyAuth(Double money, String role) {
// TODO Auto-generated method stub
return false;
}

}
[/code:1]

checkMoneyAuth是要进行业务判断的代码,最好是写在业务方法里面,然后就可以在数据库里面读取了,变动什么的都没有问题,然后再IOC进来。这个Voter比较简单,实现应该没什么问题。

注意这里取角色是根据acegi默认的ROLE_开头的来取,可以跟据自己的系统不同来改变。
   
0 请登录后投票
时间:2006-01-03
最后把这个投票者给businessAccessDecisionManager就搞定了。

[code:1]
<bean id="appropriatingFundsVoter" class="com.xxx.voter.AppropriatingFundsVoter">

<bean id="businessAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
......
<ref local="appropriatingFundsVoter"/>
</list>
</property>
</bean>
[/code:1]

其实这样实现的意义不大,只是为了说明问题,也是为了给楼主抛砖引玉。至少这样做,能让你的业务权限校验成为可插拔的了,呵呵。。
   
0 请登录后投票
时间:2006-01-03
至于第二个需求也是一样,拦截传进来的帖子的id,然后看看role,ok。当然你这个是典型的acl需求,所以建议看看acegi的acl例子,跟你的需求是一样的。
   
0 请登录后投票
时间:2006-01-04
非常感谢 差沙 大大的热情指导,感激之致,现正仔细学习中。。。进一步交流。。。
   
0 请登录后投票
时间:2006-01-04
觉得这个问题确实是一直以来权限系统的一个问题关注点,尽管权限系统本身来讲一直强调不陷入细节,但至少要提供一个支撑的框架,我觉得目前的更多的权限系统的实现级别都在系统操作的控制级别上,而至于到数据级、实例级的则还没有很好的支持模式,这种需求在实际的项目中有很多,比如只有文件夹的创始人可以做什么,然后同时他可以授权给别人,文件自动继承文件夹的权限等之类的问题,这种我称为数据权限,我觉得一个完整的权限系统应该包含对于系统操作的控制以及对于系统数据的控制。
数据权限实现本身来讲和现有的系统操作权限控制思路大致一样,把数据当为一种资源,结合对数据的操作即构成了权限,只是这里对于权限继承的要求增加到了资源部分,同时该权限一般来说需要可以授予给角色、用户或组织机构,在这种情况下,ACL的实现无疑更优于RBAC,通常都是采用两者的结合体来实现。
在实现了数据权限的这种权限系统中,象上面所说的问题和场景都是可以解决的,甚至用户对于每条数据都可以进行权限的配置,当然,这同时增加了无畏的操作复杂度,但这点要避免并不难,^_^
关于数据权限可参见我以前写过的一篇blog:
http://www.blogjava.net/BlueDavy/archive/2005/10/09/15091.html
同时,象这种场景中的何谓权限控制、何谓业务逻辑确实是值得探讨的部分。
   
0 请登录后投票
论坛首页 Java版 Spring

跳转论坛:
JavaEye推荐