接学习笔记13
4. 处理异常
Spring filter会抛出AuthenticationException和AccessDeniedException两种异常。如果不对其进行处理,它们就会被转到servlet容器中并直接显示在浏览器上。这种方式显然不友好。这时,我们就需要ExceptionTranslationFilter的帮忙。ExceptionTranslationFilter配置在FilterSecurityInterceptor的外层,这样它就可以捕获FilterSecurityInterceptor抛出的异常。ExceptionTranslationFilter的配置方法如下:
<bean id=”execeptionTranslationFilter”
class=”org.acegisecurity.ui.ExceptionTranslationFilter”>
<property name=”authenticationEntryPoint”
ref=”authenticationEntryPoint”/>
</bean>
ExceptionTranslationFilter被注入了一个authenticationEntryPoint的引用。如果捕获到异常,这意味着用户并没有通过身份验证。因此用户就会被转到由authenticationEntryPoint指定的入口点重新登录。
·处理身份验证异常
AccessDeniedException异常表明用户通过身份验证但没有足够权限访问资源。这种情况下,HTTP403错误将会返回给浏览器。HTTP403表示“被禁止”,这说明用户没有权限访问资源。
默认情况下,ExceptionTranslationFilter使用AccessDeniedHandlerImp处理AccessDeniedException异常。除非做其他配置,否则AccessDeniedHandlerImp只会返回HTTP403错误,但这可不是很友好的。
我们可以配置自己的AccessDeniedHandlerImpl以更好的方式来展示捕获AccessDeniedException时的错误页面。下面XML代码即配置一个AccessDeniedHandlerImp将用户转向一个错误页面:
<bean id=”accessDeniedHandler” class=”…AccessDeniedHandlerImp” >
<property name=”errorPage” value=”/error.htm” />
</bean>
剩下的工作就是将accessDeniedHandler加到ExceptionTranslationFilter中:
<bean id=”exceptionTranslationFilter” class=”…ExceptionTranslationFilter”>
<property name=”authenticationEntryPoint”
ref=”authenticationEntryPoint” />
<property name=”accessDeniedHandler” ref=”accessDeniedHandler” />
</bean>
我们已经学习了Spring 4个filter中的三个。下面开始学习FilterSecurityInterceptor。
5. 实施web安全
在Spring中,有一个filter安全拦截器负责拦截用户请求,确定该请求是否安全,并且会调用认证管理器和访问决策管理器来验证用户身份和权限信息。在Spring中该拦截器配置如下:
<bean id=”filterSecurityInterceptor” class=”..web.FilterSecurityInterceptor”>
<property name=”authenticationManager” ref=” authenticationManager”/>
<property name=”accessDecisionManager”
ref=” accessDecisionManager”/>
<property name=”objectDefinitionSource”>
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/editProfile.htm=ROLE_MOTORIST
</value>
</property>
</bean>
当用户请求到来时,FilterSecurityInterceptor会从以下方面检查用户是否有权限访问资源:
·用户身份合法?如果不合法,抛出AuthenticationException异常(该异常由异常filter处理)。
·所请求资源是否需要受安全保护?objectDefinitionSource属性就定义了哪些资源需要被保护,以及访问它们需要哪些权限。如果请求中的URL匹配objectDefinitionSource中定义的URL模式,那么资源是安全的。
·用户是否有足够权限访问资源?如果没有抛出AccessDeniedException异常,交由异常filter处理。
FilterSecurityInterceptor会调用认证管理器和访问决策管理器来做上述检查。objectDefinitionSource属性指定了哪些资源受安全保护以及哪些权限可以访问资源。值得注意的是最后一行,我们指定了只有拥有ROLE_MOTORIST权限的用户次啊能访问editProfile.htm页面。
至此,我们已经配置了一些最基本的filter,但还是有个filter需要配置,虽然不是必需,但它可以很方便地确保受保护的信息可以安全地被传递。这就是ChannelProcessingFilter。
6. 确保安全通道
使用https,信息仍然通过HTTP传输,但是被加密起来发送到一个不同的端口。但是HTTPs也有缺点,那就是你必须以https开头,如果你漏泄了s,那么数据信息就会以未加密的方式任意通过http传输。因为人们太容易遗漏s,所以Spring提供了一种简单的方式来确保某些页面确实使用HTTPS来传输。如图:
从上图可以发现,ChannelProcessingFilter会拦截请求,检查它是否需要被安全保护。如果需要,那么重定向请求到一个https方式。ChannelProcessingFilter配置方法如下,以RoadRantz应用为例:
<bean id=”channelProcessingFilter”
class=”..secureChannel.ChannelProcessingFilter”>
<property name=”filterInvocationDefinitionSource”>
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/login.htm=REQUIRES_SECURE_CHANNEL
/j_acegi_security_check*=REQUIRES_SECURE_CHANNEL
/**=REQUIRES_INSECURE_CHANNEL
</value>
</property>
<property name=”channelDecisionManager”
ref=” channelDecisionManager” />
</bean>
配置filterInvocationDefinitionSource属性用于告诉ChannelProcessingFilter哪些页面需要https保护以及哪些不需要。我们需要为它配置一个或多个URL模式来分别匹配那些需要的和不需要的。
对于RoadRantz应用来说,登录页面必须要受保护的。因此,/login.htm被映射到REQUIRES_SECURE_CHANNEL,表明它应该使用HTTPS。同样,用于处理登录的URL信息也必须被加密。AuthenticationProcessingFilter对应于/j_acegi_security_check,这样这个URL模式也被设置成REQUIRES_SECURE_CHANNEL。
其他的任何页面都不需要加密,所以/** URL模式(表明所有的URL)都被设置成REQUIRES_INSECURE_CHANNEL,表明它们必须在HTTP上传输。这些页面需要一个非受保护通道。这就说明如果经由HTTPS传输,ChannelProcessingFilter会将它们重定向到HTTP。
·通道决策
ChannelProcessingFilter负责HTTP和HTTPS间的重定向,但是它并不需要重定向每个请求。这依赖于ChannelDecisionManagerImpl。ChannelDecisionManagerImpl将会决定一个请求是否需要被重定向。配置如下:
<bean id=”channelDecisionManager” class=”ChannelDecisionManagerImpl”>
<property name=”channelProcessors”>
<list>
<bean class=”…SecureChannelProcessor” />
<bean class=”..InsecureChannelProcessor” />
</list>
</property>
</bean>
ChannelDecisionManagerImpl有两个channel属性,一个用于HTTPS,一个用于HTTP。