Spring Security支持的基础设施

这章里讨论一些Spring Security中用到的基础设施。 如果这个功能跟安全没有直接关系,但是还是包含在Spring Security中了,我们就在这章里讨论它。

6.1. 国际化

Spring Security支持异常信息的国际化,最终用户会很喜欢这点。 如果你的程序是为英语用户设计的,你不需要做任何事,因为默认情况下所有的Spring Security消息都是英文的。 如果你需要支持其他语言,你所需要做的就是看看这节内容。

所有的异常信息都是可以本地化的,包括验证失败和访问被拒绝(验证失败)信息。 开发者和系统发布者关注的异常和日志信息(包括不正确的属性,接口联系分隔,使用错误的构造器,开始验证册书,日志调试等级)等等,不能进行本地化,而是使用英文直接硬编码到了Spring Security代码里。

打开spring-security-core-xx.jar,你可以找到org.springframework.security包,里面包含了一个messages.properties文件。 你的ApplicationContext应用应该引用这个文件,因为Spring Security实现了Spring的MessageSourceAware接口,希望这些消息会在application context启动的时候注入到程序中。 通常,你需要做的就是,在你的application context 里注册一个bean,来引用这些信息,比如像下面这样:

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
  <property name="basename" value="org/springframework/security/messages"/>
</bean>

这个messages.properties使用了标准的资源束命名方式,为Spring Security提供了默认的语言支持。 默认的语言是英文。 如果你没有注册消息源,Spring Security依然可以正常工作,但是使用的是硬编码的英文信息版本。

如果你想自定义messages.properties文件,或支持其他语言,你应该复制这个文件,改成对应的文件名,并把它注册到上面的bean定义中。 文件里的关键信息并不多,本地化应该不是一个很大的任务。 如果你对这个文件进行了本地化,请考虑把你的工作与社区分享,记录一个JIRA任务,把你的本地化版本messages.properties以附件形式发送上来。

围绕本地化进行讨论,就要提到Spring里的ThreadLocalorg.springframework.context.i18n.LocaleContextHolder。 你应该通过LocaleContextHolder,来表现每个用户想要的Locale. Spring Security尝试从信息源中定位信息,使用从ThreadLocal里中获得的Locale。 请参考Spring文档获得使用LocaleContextHolder的更多信息,可以使用一些帮助类进行自动设置(比如AcceptHeaderLocaleResolver, CookieLocaleResolver, FixedLocaleResolver, SessionLocaleResolver等等)。

6.2. 过滤器

Spring Security用到了很多过滤器,参考指南的后续部分会一一提到。 如果你使用了命名空间配置,你就不用经常去明确指定过滤器bean。 有几种可能情况,你希望对安全过滤器链进行完全控制,或许因为你使用的功能没法使用命名空间进行支持,或者你使用了自己自定义版本的类。

这种情况下,你可以选择向你的web应用成立里添加哪些过滤器,这里你可以使用Spring的DelegatingFilterProxyFilterChainProxy。我们会在下面介绍它们两个。

在使用DelegatingFilterProxy的时候,你会看到web.xml里这样的内容:

    <filter>
        <filter-name>myFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
      <filter-name>myFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
        

注意这个过滤器其实是一个DelegatingFilterProxy,这个过滤器里没有实现过滤器的任何逻辑。 DelegatingFilterProxy做的事情是代理Filter的方法,从application context里获得bean。 这让bean可以获得spring web application context的生命周期支持,使配置较为轻便。 bean必须实现javax.servlet.Filter接口,它必须和filter-name里定义的名称是一样的。

在生命周期的问题上,要考虑在IoC容器里而不是在servlet容器里管理Filter。 具体来说,到底是哪个容器应该调用Filter的“启动”与“关闭”方法。 需要指出的是Filter的初始化和销毁很容易受servlet容器的影响,如果一个Filter依赖于较早初始化Filter的配置,那么可能会引发一些问题。 Spring IoC容器,从另一方面讲,拥有更强大的生命周期/IoC接口(比如InitializingBean, DisposableBean, BeanNameAware, ApplicationContextAware和很多其他的),拥有更容易理解的接口协议,可预见的方法调用顺序,支持自动绑定,更可以选择不用实现Spring的接口(比如通过Spring XML中的destroy-method属性)。 介于这些原因,只要有可能的话,我们推荐使用Spring生命周期服务,代替servlet容器的生命周期。 可以参考DelegatingFilterProxy的Javadoc获得更多信息。

最好别用DelegatingFilterProxy,我们强烈推荐你使用FilterChainProxy代替它。 虽然DelegatingFilterProxy是一个非常有用的类,问题是在需要使用几个过滤器的时候,需要在web.xml中定义<filter><filter-mapping>入口的代码数量太多了。 为了解决这个问题,Spring Security提供了一个FilterChainProxy类。 它绑定了一个DelegatingFilterProxy(好像上面的例子那样),但是使用的类是org.springframework.security.util.FilterChainProxy。 过滤器链要声明在application context里,使用下面的代码:

<bean id="filterChainProxy" class="org.springframework.security.util.FilterChainProxy">
  <sec:filter-chain-map path-type="ant">
     <sec:filter-chain pattern="/webServices/**"
         filters="httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor"/>
     <sec:filter-chain pattern="/**"
         filters="httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor"/>
  </sec:filter-chain-map>
</bean>

    

你可能注意到FilterSecurityInterceptor声明的不同方式。 它同时支持正则表达式和ant路径,并且只使用第一个出现的匹配URI。 在运行阶段FilterChainProxy会定位当前web请求匹配的第一个URI模式,由filters属性指定的过滤器bean列表将开始处理请求。 过滤器会按照定义的顺序依次执行,所以你可以对处理特定URL的过滤器链进行完全的控制。

你可能注意到了,我们在过滤器链里声明了两个HttpSessionContextIntegrationFilterASCallowSessionCreation的简写,是HttpSessionContextIntegrationFilter的一个属性)。 因为web服务从来不会在请求里带上jsessionid,为每个用户代理都创建一个HttpSession完全是一种浪费。 如果你需要构建一个高等级最高可扩展性的系统,我们推荐你使用上面的配置方法。 对于小一点儿的项目,使用一个HttpSessionContextIntegrationFilter(让它的allowSessionCreation默认为true)就足够了。

在有关声明周期的问题上,如果这些方法被FilterChainProxy自己调用,FilterChainProxy会始终根据下一层的Filter代理init(FilterConfig)destroy()方法。 这时,FilterChainProxy会保证初始化和销毁操作只会在Filter上调用一次,而不管它们被FilterInvocationDefinitionSource声明了多少次。 你可以完全控制是否调用这些方法,通过代理DelegatingFilterProxytargetFilterLifecycle初始化参数,。 像上面讨论的那样,默认的servlet容器生命周期调用不会被DelegatingFilterProxy代理。

在使用命名空间配置的时候,你可以通过同样的方式使用filters = "none"属性,来建立FilterChainProxy。 这将从安全过滤器链中完全忽略请求的模式。 注意,任何匹配这个路径的请求,不会要求认证,不会使用验证服务,可以自由的访问。

定义在web.xml里的过滤器的顺序是非常重要的。 不论你实际使用的是哪个过滤器,<filter-mapping>的顺序应该像下面这样:

  1. ChannelProcessingFilter,因为它可能需要重定向到其他协议。

  2. ConcurrentSessionFilter,因为它不使用SecurityContextHolder功能,但是需要更新 SessionRegistry 来从主体中放映正在进行的请求。

  3. HttpSessionContextIntegrationFilter,这样 SecurityContext可以在web请求的开始阶段通过 SecurityContextHolder建立,然后 SecurityContext的任何修改都会在web请求结束的时候(为下一个web请求做准备)复制到 HttpSession中。

  4. 验证执行机制 - AuthenticationProcessingFilter, CasProcessingFilter, BasicProcessingFilter, HttpRequestIntegrationFilter, JbossIntegrationFilter 等等 - 这样 SecurityContextHolder 可以被修改,并包含一个合法的 Authentication 请求标志。

  5. SecurityContextHolderAwareRequestFilter,如果,你使用它,把一个Spring Security提醒HttpServletRequestWrapper安装到你的servlet容器里。

  6. RememberMeProcessingFilter,这样如果之前的验证执行机制没有更新 SecurityContextHolder,这个请求提供了一个可以使用的remember-me服务的cookie,一个对应的已保存的 Authentication对象会被创建出来。

  7. AnonymousProcessingFilter,这样如果之前的验证执行机制没有更新 SecurityContextHolder,会创建一个匿名 Authentication对象。

  8. ExceptionTranslationFilter,用来捕捉 Spring Security异常,这样,可能返回一个HTTP错误响应,或者执行一个对应的 AuthenticationEntryPoint

  9. FilterSecurityInterceptor,保护web URI。

上面所有的过滤器,都使用了 DelegatingFilterProxyFilterChainProxy。推荐使用单独的 DelegatingFilterProxy 为每个程序代理一个单独的 FilterChainProxy,通过这个 FilterChainProxy 定义Spring Security的所有过滤器。

如果你使用了SiteMesh,一定要确保Spring Security过滤器在SiteMesh的过滤器之前被调用。 这才可以保证为SiteMesh渲染器使用的 SecurityContextHolder 先被组装起来。

6.3. 标签库

Spring Security捆绑了很多JSP标签库,提供了各种不同的服务。

6.3.1. 配置

所有的taglib类都包含在核心spring-security-xx.jar文件里, security.tld文件放在JAR的META-INF目录下。 这意味着,对于JSP 1.2+的web容器,你可以直接把JAR放到WAR的WEB-INF/lib目录下,然后就可以用了。 如果你使用的是JSP 1.1 容器,你需要在你的web.xml文件里声明JSP taglib,还要把security.tld放到WEB-INF/lib目录下。 把下面的片段添加到web.xml里:

<taglib>
  <taglib-uri>http://www.springframework.org/security/tags</taglib-uri>
  <taglib-location>/WEB-INF/security.tld</taglib-location>
</taglib>

6.3.2. 使用

现在你已经配置好了标签库,可以转到单独的参考指南章节,阅读如何使用他们的详细信息。 注意当使用标签时,你应该在你的JSP里包含taglib引用:

  <%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %>

        

本文转自:http://www.family168.com/tutorial/springsecurity/html/supporting-infrastructure.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值