最近在整合Spring-Security中的ACL域模型保护的时候碰到一个问题。相关部分的配置如下:<!-- filter the user request with a cutome definition source which fecth security configs from rdbms -->
<bean id="filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="accessDecisionManager" />
<property name="objectDefinitionSource"><!-- use the custom definition source -->
<bean class="cn.edu.ccnu.inc.webtemplate.security.interceptor.SpringSecurityDBFilterInvocationDefinitionSource">
<property name="useAntPath" value="true" />
<property name="convertUrlToLowercaseBeforeComparison" value="true" />
<property name="securityCacheManager" ref="securityCacheManager" />
</bean>
</property>
</bean>        <bean id="methodSecurityInterceptor" class="org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="accessDecisionManager" />
<property name="afterInvocationManager" ref="afterInvocationManager" />
<property name="objectDefinitionSource">
<bean class="cn.edu.ccnu.inc.webtemplate.security.interceptor.DBMethodInvocationDefinitionSource">
<property name="securityCacheManager" ref="securityCacheManager" />
</bean>
</property>
</bean> <!-- access decision manager -->
<bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false" />
<property name="decisionVoters">
<list>
<ref local="roleVoter" />
<ref local="aclAppUserReadVoter" />
<ref local="aclAppUserWriteVoter" />
<ref local="aclAppUserDeleteVoter" />
<ref local="aclAppUserAdminVoter" />
</list>
</property>
</bean>        <!-- An access decision voter that reads ACL_APPUSER_READ configuration settings -->
<bean id="aclAppUserReadVoter" class="org.springframework.security.vote.AclEntryVoter">
<constructor-arg ref="aclService" />
<constructor-arg value="ACL_APPUSER_READ" />
<constructor-arg>
<list>
<ref local="org.springframework.security.acls.domain.BasePermission.READ" />
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION" />
</list>
</constructor-arg>
<property name="processDomainObjectClass" value="cn.edu.ccnu.inc.webtemplate.model.AppUser" />
</bean>
...............................但是在启动时会报如下的错误(最根本的异常):java.lang.IllegalArgumentException: AccessDecisionManager does not support secure object class: class org.springframework.security.intercept.web.FilterInvocation
at org.springframework.util.Assert.isTrue(Assert.java:65)
at org.springframework.security.intercept.AbstractSecurityInterceptor.afterPropertiesSet(AbstractSecurityInterceptor.java:178)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:168)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:884)
at org.springframework.security.intercept.web.FIDSToFilterChainMapConverter.<init>(FIDSToFilterChainMapConverter.java:54)
..........大致的跟踪了一下,主要的错误来自于AbstractSecurityInterceptor.afterPropertiesSet,代码如下:public void afterPropertiesSet() throws Exception {
        Assert.notNull(getSecureObjectClass(), "Subclass must provide a non-null response to getSecureObjectClass()");
        Assert.notNull(this.messages, "A message source must be set");
        Assert.notNull(this.authenticationManager, "An AuthenticationManager is required");
        Assert.notNull(this.accessDecisionManager, "An AccessDecisionManager is required");
        Assert.notNull(this.runAsManager, "A RunAsManager is required");
        Assert.notNull(this.obtainObjectDefinitionSource(), "An ObjectDefinitionSource is required");
        Assert.isTrue(this.obtainObjectDefinitionSource().supports(getSecureObjectClass()),
                "ObjectDefinitionSource does not support secure object class: " + getSecureObjectClass());
        Assert.isTrue(this.runAsManager.supports(getSecureObjectClass()),
                "RunAsManager does not support secure object class: " + getSecureObjectClass());
        Assert.isTrue(this.accessDecisionManager.supports(getSecureObjectClass()),
                "AccessDecisionManager does not support secure object class: " + getSecureObjectClass());        if (this.afterInvocationManager != null) {
            Assert.isTrue(this.afterInvocationManager.supports(getSecureObjectClass()),
                    "AfterInvocationManager does not support secure object class: " + getSecureObjectClass());
        }.............................大意就是这里的 AccessDecisionManager 不支持 FilterInvocation ,看了源代码后发现,确实,AclVoter 是不支持 FilterInvocation 的,在 AbstractAclVoter 中有如下的判断:    /**
     * This implementation supports only <code>MethodSecurityInterceptor</code>, because it queries the
     * presented <code>MethodInvocation</code>.
     *
     * @param clazz the secure object
     *
     * @return <code>true</code> if the secure object is <code>MethodInvocation</code>, <code>false</code> otherwise
     */
    public boolean supports(Class clazz) {
        if (MethodInvocation.class.isAssignableFrom(clazz)) {
            return true;
        } else if (JoinPoint.class.isAssignableFrom(clazz)) {
            return true;
        } else {
            return false;
        }
    }它只对方法拦截提供支持,而对资源访问控制并不支持。
在下对ACL领域模型的保护确实研究不多,上面关于 AccessDecisionManager 的配置也是参考了网上一些教程,不知道该如何修改,当然如果再给 MethodInvocationInterceptor 单独设置一个 AccessDecisionManager 应该可以解决问题,或者修改AclVoter的源码,对FilterInvocation提供支持也可以,但是觉得这样太暴力了,而且也没看过哪位仁兄这样配置的,大分部好像都共享一个 AccessDecisionManager 就可以了。希望哪位仁兄做过这方面的配置,能给在下提供一些帮助,给一些配置的样例(网上有一些例子,但好像都是单纯的配置资源保护或是方法调用保护,而没有整合ACL DOMAIN保护一起的配置)。