【转】Acegi ACL使用(转载) 收藏

Acegi ACL使用(转载) 收藏
 本文假设你对Acegi其他部分已经比较熟悉。Acegi 的ACL控制是建立在对相应业务方法拦截的基础上的。这里以Acegi自带的contacts例子来说明。
先看看总的配置:

xml 代码
 
1.<bean id="contactManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"> 
2.      <property name="authenticationManager"><ref bean="authenticationManager"/>property> 
3.      <property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/>property> 
4.      <property name="afterInvocationManager"><ref local="afterInvocationManager"/>property> 
5.      <property name="objectDefinitionSource"> 
6.         <value> 
7.            sample.contact.ContactManager.getAll=AFTER_ACL_COLLECTION_READ 
8.            sample.contact.ContactManager.getById=AFTER_ACL_READ 
9.            sample.contact.ContactManager.delete=ACL_CONTACT_DELETE 
10.            sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN 
11.            sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN 
12.         >  13.      >  
14.   bean> 

该 拦截器实现了org.aopalliance.intercept.MethodInterceptor接口。在方法被调用之前,拦截器会先调用 AuthenticationManager判断用户身份是否已验证,然后从objectDefinitionSource中获取方法所对应的权限,再调 用AccessDecisionManager来匹配用户权限和方法对应的权限。如果用户没有足够权限调用当前方法,则抛出 AccessDeniedException使方法不能被调用。方法调用后会调用AfterInvocationManager对返回的结果进行再次处 理。下面依次说明。
AccessDecisionManager的配置:

xml 代码
 
1.<bean id="businessAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"> 
2.      <property name="allowIfAllAbstainDecisions"><value>falsevalue>property> 
3.      <property name="decisionVoters"> 
4.         <list> 
5.            <ref local="roleVoter"/> 
6.            <ref local="aclContactReadVoter"/> 
7.            <ref local="aclContactDeleteVoter"/> 
8.            <ref local="aclContactAdminVoter"/> 
9.         list> 
10.      property> 
11.   bean> 

AccessDecisionManager 接口有decide()和support()方法。decide()方法决策是否批准通过即方法是否容许调用,如果没抛出 AccessDeniedException则为允许访问资源,否则拒绝访问。support()方法是根据配置属性和受保护资源的类来判断是否需要对该 资源作出决策判断。
AccessDecisionManager的 decisionVoters属性需要一个或多个Voter(投票者),Voter必须实现AccessDecisionVoter 接口。Voter的工作是去匹配用户已拥有的权限和受保护的资源要求的权限,在该资源有相应权限的情况下,如果匹配则投允许票,否则投反对票。
allowIfAllAbstainDecisions属性表示是否允许所有都弃权时就通过。Voter的实现类RoleVoter在当受保护资源的名字由ROLE_开始时才参与投票。
AccessDecisionManager有三个实现类,功能各不相同:
AffirmativeBased: 当至少有一个Voter投允许票时才通过
UnanimousBased: 没有Voter投反对票时才通过
ConsensusBased: 当所有Voter都投允许票时才通过
下面列出一个Voter的配置:

xml 代码
 
1.<bean id="aclContactDeleteVoter" class="org.acegisecurity.vote.BasicAclEntryVoter"> 
2.      <property name="processConfigAttribute"><value>ACL_CONTACT_DELETEvalue>property> 
3.      <property name="processDomainObjectClass"><value>sample.contact.Contactvalue>property> 
4.      <property name="aclManager"><ref local="aclManager"/>property> 
5.      <property name="requirePermission"> 
6.        <list> 
7.          <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/> 
8.          <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/> 
9.        <list> 
10.      <property> 
11.   <bean> 

上面第一个配置里有这么一行:sample.contact.ContactManager.delete=ACL_CONTACT_DELETE
所 以在调用sample.contact.ContactManager.delete这个方法时aclContactDeleteVoter会参与投票, 它会获得sample.contact.Contact这个对象(这个对象从delete方法的参数中获得),然后通过aclManager去获得当前用 户对该Contact实例的ACL权限,最后拿这个权限与我们需要的权限比对,我们配置需要的权限是 org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION和 org.acegisecurity.acl.basic.SimpleAclEntry.DELETE。如果我们通过aclManager获得的权限包 括这两个配置的权限之一,Voter就投容许票,方法容许调用。如果不包括,那对不起,反对票,AccessDecisionManager就会抛出 AccessDeniedException。方法拒绝调用。
AclManager的配置:

xml 代码
 
1.<bean id="aclManager" class="org.acegisecurity.acl.AclProviderManager"> 
2.      <property name="providers"> 
3.         <list> 
4.            <ref local="basicAclProvider"/> 
5.         <list> 
6.      <property> 
7.   <bean> 
8. 
9.   <bean id="basicAclProvider" class="org.acegisecurity.acl.basic.BasicAclProvider"> 
10.      <property name="basicAclDao"><ref local="basicAclExtendedDao"/><property> 
11.   bean> 
12. 
13.   <bean id="basicAclExtendedDao" class="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl"> 
14.      <property name="dataSource"><ref bean="dataSource"/><property> 
15.   <bean> 

AclManager是整个ACL中一个很核心的概念,它包含了两个方法AclEntry[] getAcls(Object domainInstance)和
AclEntry[] getAcls(Object domainInstance, Authentication authentication)。在了解这两个方法前,我们先了解AclEntry这个对象。AclEntry只是一个接口,系统中一般都是造型为 BasicAclEntry。它包括了这个Entry所保护的domainObject instance(这里是Contact),实际它实现上是以AclObjectIdentity来替代这个domainObject的 (domainClass+domainObjectId);它包括了谁(Recipient)拥有这个domainObject instance以及他所对这个domainObject instance的操作权限(mask)。
一个domainObject instance对应了多个AclEntry,比如一条通讯录张三可以查看,而李四可以管理,一个Contact instance就对应了两个AclEntry,第一个AclEntry包含信息:所保护的domainObject(Contact),谁(张三),权 限(查看);第二个AclEntry包含信息:所保护的domainObject(Contact),谁(李四),权限(管理)。
这样AclManager的两个方法就很好理解了getAcls(Object domainInstance)返回所有这个domainInstance所对应的权限信息,
getAcls(Object domainInstance, Authentication authentication)在第一个方法返回结果的基础上做了过滤,过滤出和authentication(当前用户)相关的权限信息。如果当前用户 是张三,则返回与张三对应的记录。

这样Acegi就会拦截业务方法发挥相应的作用,但是在业务方法返回一个List或是单个 domainObject instance的时候,同样也是需要把用户没有权限查看的domainObject instance过滤掉的,这时就要用afterInvocationManager了,看配置:

xml 代码
 
1.<bean id="afterInvocationManager" class="org.acegisecurity.afterinvocation.AfterInvocationProviderManager"> 
2.      <property name="providers"> 
3.         <list> 
4.            <ref local="afterAclRead"/> 
5.            <ref local="afterAclCollectionRead"/> 
6.         </list> 
7.      </property> 
8.   </bean> 
9.    
10.   <!-- Processes AFTER_ACL_COLLECTION_READ configuration settings --> 
11.   <bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider"> 
12.      <property name="aclManager"><ref local="aclManager"/></property> 
13.      <property name="requirePermission"> 
14.        <list> 
15.          <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/> 
16.          <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/> 
17.        </list> 
18.      </property> 
19.   </bean> 
20.    
21.   <!-- Processes AFTER_ACL_READ configuration settings --> 
22.   <bean id="afterAclRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider"> 
23.      <property name="aclManager"><ref local="aclManager"/></property> 
24.      <property name="requirePermission"> 
25.        <list> 
26.          <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/> 
27.          <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/> 
28.        </list> 
29.      </property> 
30.   </bean> 

afterAclCollectionRead 会对配置AFTER_ACL_COLLECTION_READ的方法进行拦截,这里是 sample.contact.ContactManager.getAll方法,它会遍历方法返回的domainObject,然后挨个通过 aclManager判断当前用户对domainObject的权限,如果和需要的权限不和,则过滤掉。呵呵,传说中的虎牙子就在此时产生了!
afterAclRead则依次类推。
参考了ss wiki里相关的文档,特别是差沙和cac的文档,写的相当好。另外acegi的代码也是相当的易读。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/anyoneking/archive/2007/09/04/1771688.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值