使用代理过滤器链对处理HTTP请求 Acegi通过众多的过滤器完成不同
安全控制的任务,在前面我们提到了三个过滤器:HttpSessionContextIntegrationFilter、ExceptionTranslationFilter和ChannelProcessingFilter。除此以外,还有LogoutFilter、AuthenticationProcessingFilter等不下10个的过滤器。
当需要配置多个Servlet过滤器时,虽然我们可以通过FilterToBeanProxy分别进行配置,但这将导致冗长难看的web.xml,同时还需要小心谨慎地通过过滤器的配置顺序保证它们的调用顺序。为了解决这个问题,Acegi在0.8版本中添加了一个org.acegisecurity.util.FilterChainProxy。FilterChainProxy可以同时指定多个过滤器并将它们组成一个过滤器链,而FilterToBeanProxy只要将代理目标设置为FilterChainProxy就可以了。来看下面的配置:
代码清单 1 web.xml
<web-app>
<context-param> ①指定Spring配置文件
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml,
classpath:applicationContext-acegi-plugin.xml
</param-value>
</context-param>
<filter>②将过滤器委托给FilterChainProxy
<filter-name>AcegiFilterChainProxy</filter-name>
<filter-class>
org.acegisecurity.util.FilterToBeanProxy
</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>
org.acegisecurity.util.FilterChainProxy
</param-value>
</init-param>
</filter>
<filter-mapping>③对所有的URL进行过滤
<filter-name>AcegiFilterChainProxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
…
</web-app>
在web.xml中我们首先需要定义Spring的配置文件,以便将Spring容器集成到Servlet容器中。紧接着,我们定义一个FilterToBeanProxy的过滤器拦截所有URL请求并委托给FilterChainProxy进行处理。FilterChainProxy在Spring容器中定义如下所示:
代码清单 2 applicationContext-acegi-plugin.xml
<beans>
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">①目标委托的Bean
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_UPPERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
②多个过滤器组成的过滤器链
/**=channelProcessingFilter,httpSessionContextIntegrationFilter,logoutFilter
</value>
</property>
</bean>
<bean id="channelProcessingFilter" ③过滤器链中的过滤器(1)
class="org.acegisecurity.securechannel.ChannelProcessingFilter">
…
</bean>
<bean id="httpSessionContextIntegrationFilter" ④过滤器链中的过滤器(2)
class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
…
</bean>
…
</beans>
在①处定义的FilterChainProxy Bean是web.xml的FilterToBeanProxy的委托目标。FilterChainProxy通过filterInvocationDefinitionSource定义多个相互链接的过滤器,如②所示。这些过滤器以逗号分隔,它表示web.xml中定义的匹配URL(/*)请求将分别通过channelProcessingFilter、httpSessionContextIntegrationFilter及logoutFilter这三个过滤器的拦截处理。这个过滤器链通过过滤器对应的Bean名字(如③和④)进行定义,过滤器都实现了javax.servlet .Filter接口。你完全可以参照实例方式定义多组滤器链,以便处理不同URL请求。不过,在一般情况下,你只要配置一个过滤器链就可以了。
filterInvocationDefinitionSource属性由两类信息组成:其一是指令信息,如
CONVERT_URL_TO_UPPERCASE_BEFORE_COMPARISON表示判断URL匹配时,首先将URL转变为大写的格式,如果设置为CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON则表示比较前事先转换为小写的形式。而PATTERN_TYPE_APACHE_ANT表示使用Ant路径风格进行匹配URL的描述,如果不提供这个指令,Acegi使用正则表达式来解析URL路径映射。