第 42 章 设置过滤器链

对于不是从acegi升级到spring security的同志们,用多了命名空间这种配置方式,肯定在抱怨它的扩展性不够。现在我们就来展示一下在acegi中屡遭诟病的自定义过滤器链配置方式。

警告

acegi当年就是以这种配置方式,被冠以“每使用一次acegi,世界的某个地方就会有一个精灵死掉”的称号,请各位慎用。

既然不再使用http标签,我们就需要在配置文件中手工声明一个springSecurityFilterChain,这个bean会由web.xml中的DelegatingFilterProxy调用,注意bean的id必须为springSecurityFilterChain,否则系统启动时会报错。

下面我们就在springSecurityFilterChain中配置多个过滤器链。

<bean id="springSecurityFilterChain"
    class="org.springframework.security.web.FilterChainProxy">
    <sec:filter-chain-map path-type="ant">
        <sec:filter-chain pattern="/spring_security_login"
            filters="loginPageFilter" />
        <sec:filter-chain pattern="/j_spring_security_check*"
            filters="httpSessionContextIntegrationFilter,authenticationProcessingFilter" />
        <sec:filter-chain pattern="/**"
            filters="httpSessionContextIntegrationFilter,
                     exceptionTranslationFilter,
                     filterInvocationInterceptor" />
    </sec:filter-chain-map>
</bean>
    

这里我们配置了三套过滤器链,loginPageFilter负责处理/spring_security_login,httpSessionContextIntegrationFilter,authenticationProcessingFilter用来处理/j_spring_security_check*,最后由其他三个过滤器处理其外的所有URL请求。

loginPageFilter用来生成登录页面,authenticationProcessingFilter用来处理用户登录请求,只是它还需要与httpSessionContextIntegrationFilter一同起作用才能完成用户登录。这三个过滤器的配置如下:

<bean id="httpSessionContextIntegrationFilter"
    class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>

<bean id="loginPageFilter" class="org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter">
    <constructor-arg ref="authenticationProcessingFilter"/>
</bean>

<bean id="authenticationProcessingFilter"
    class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    <property name="authenticationManager" ref="authenticationManager"/>
</bean>
    

其余的所有URL请求都使用httpSessionContextIntegrationFilter,exceptionTranslationFilter,filterInvocationInterceptor这三个过滤器的组合来处理,它们就是用来实际控制权限的部分。虽然这里只要配置三个过滤器,但实际上它们还需要和其他附属功能部件一起工作才能完成全县控制的功能。

比如exceptionTranslationFilter就需要authenticationEntryPoint来控制抛出异常时响应的策略和跳转的URL地址。

<bean id="authenticationEntryPoint"
    class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <property name="loginFormUrl" value="/spring_security_login"/>
</bean>

<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
    <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</bean>
    

而filterInvocationInterceptor作为最核心的权限控制拦截器还需要authenticationManager和decisionManager的配合,这里我们为了不多害死其他精灵,所以就不贴配置内容了。

最后我们可以看到,使用了这种acegi中古老的配置方法能给我们控制每个组件的权力,但是整整82行代码的配置所实现功能,也就相当于使用了命名空间配置的20行代码,明显还是使用命名空间配置方式在可维护性上更有优势。

实例在ch210中。