使用Java 5 Annotations 方式来实现方法级别的保护,配置文件如下:
<bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"> <property name="validateConfigAttributes" value="false" /> <property name="authenticationManager" ref="authenticationManager" /> <property name="accessDecisionManager" ref="accessDecisionManager" /> <property name="objectDefinitionSource"> <bean class="org.acegisecurity.intercept.method.MethodDefinitionAttributes"> <property name="attributes"> <!-- 利用1.5Annotation的設定方式 --> <bean class="org.acegisecurity.annotation.SecurityAnnotationAttributes" /> </property> </bean> </property> </bean>
此外,在代码里面必使用Acegi Java 5 Security Annotations 来配置方法的保护属性。下面的例子使用 @Secured 注解来描述配置属性,如下示例:
import org.acegisecurity.annotation.Secured; import org.springframework.transaction.annotation.Transactional; /** * 使用Java 5 注解来实现方法保护 * * @author Janwer * */ @Transactional public interface WebService { @Transactional(readOnly=true) @Secured({"ROLE_CUSTOMER"}) List<Subscribe> queryOrderStates(long regId, int subcribeStatus); @Transactional(readOnly=true) @Secured({"ROLE_MANAGER"}) List<Subscribe> queryRegSubscribeState(Page page, boolean asc, int subcribeStatus); @Secured({"ROLE_CUSTOMER"}) TransactionResult createSubscribeByAlipay(Map<String,String> m, Register r, int status, String alipayRecord); }
你可能注意到了 validateConfigAttributes 属性在上面的 MethodSecurityInterceptor 示例中,当设置为 true (the default) ,在启动时 MethodSecurityInterceptor 将验证提供的所有配置属性是否有效。它每个配置属性的检查能通过 AccessDecisionManager 或 RunAsManager 来处理。假如它们都不能处理这些配置属性,那么一个异常将会被抛出。如果使用 Jakarta Commons 属性配置方法, 你应该将 validateConfigAttributes 设置为 false 。
注意:其实使用Java 5 的注释也应该设置为false ,否则在程序启动时,将有一个警告产生。并不影响它的正常使用。
WARN [org.acegisecurity.intercept.AbstractSecurityInterceptor.afterPropertiesSet:225]- Could not validate configuration attributes as the MethodDefinitionSource did not return a ConfigAttributeDefinition Iterator
请注意,当使用 BeanNameAutoProxyCreator 为安全过滤创建请求代理时,如果使用基于 CGLIB 的代理,那配置文件应当包含 proxyTargetClass 属性并设置为 true 。否则方法保护将不起作用。引用的是代理的呼叫,而不是实际代理的对象。注意采用这种方式需要 CGLIB 。如果直接使用 JDK1.5 动态代理时,可以注释掉这一属性,见如下示例:
<!-- 利用Spring的自动代理功能实现AOP代理 --> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <value>methodSecurityInterceptor</value> </list> </property> <property name="beanNames"> <list> <!-- 需要保护的方法 --> <value>registerService</value> <value>mgrService</value> <value>subService</value> </list> </property> <!--property name="proxyTargetClass" value="true"/--> </bean>
注意:上面是引用Acegi 官方文档描述,但在我的实际使用中,因为我用的是Spring 2.0.6 且使用基于 JDK1.5 的动态代理,所以不再需要proxyTargetClass 属性设置。当然如是使用 CGLIB 代理的就按官方说明来设置。