安全过滤器链
Spring Security的web架构是彻底基于标准的servlet过滤器的。它没有在内部使用servlet或任何其余基于servlet的框架(好比spring mvc),因此它没有与任何特定的web技术强行关联。 它只管处理HttpServletRequest 和HttpServletResponse,不关心请求时来自浏览器,web服务客户端,HttpInvoker仍是一个AJAX应用。 java
Spring Security维护了一个过滤器链,每一个过滤器拥有特定的功能,过滤器须要服务也会对应添加和删除。过滤器的次序是很是重要的,它们之间都有依赖关系。 若是你已经使用了命名空间配置,过滤器会自动帮你配置, 你不须要定义任何Spring Bean,可是有时候你须要彻底控制Spring过滤器链,由于你使用了命名空间没有提供的特性,或者你须要使用你本身自定义的类。 web
1. DelegatingFilterProxy
当使用servlet过滤器时,你很须要在你的web.xml中声明它们, 它们可能被servlet容器忽略。在Spring Security,过滤器类也是定义在xml中的spring bean, 所以能够得到Spring的依赖注入机制和生命周期接口。 spring的DelegatingFilterProxy提供了在 web.xml和application context之间的联系。 正则表达式
当使用DelegatingFilterProxy,你会看到像 web.xml文件中的这样内容: spring
<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里定义的名称是同样的。查看DelegatingFilterProxy的javadoc得到更多信息。 数据库
2. FilterChainProxy
如今应该清楚了,你能够声明每一个Spring Security过滤器bean,你在application context中须要的。把一个DelegatingFilterProxy入口添加到web.xml, 确认它们的次序是正确的。这是一种繁琐的方式,会让web.xml显得十分杂乱,若是咱们配置了太多过滤器的话。咱们最好添加一个单独的入口,在web.xml中,而后在application context中处理实体,管理咱们的web安全bean。 这就是FilterChainProxy所作的事情。它使用DelegatingFilterProxy (就像上面例子中那样),可是对应的class是org.springframework.security.web.FilterChainProxy。过滤器链是在application context中声明的。这里有一个例子: 浏览器
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy"> <sec:filter-chain-map path-type="ant"> <sec:filter-chain pattern="/webServices/**" filters=" securityContextPersistenceFilterWithASCFalse, basicAuthenticationFilter, exceptionTranslationFilter, filterSecurityInterceptor" /> <sec:filter-chain pattern="/**" filters=" securityContextPersistenceFilterWithASCFalse, formLoginFilter, exceptionTranslationFilter, filterSecurityInterceptor" /> </sec:filter-chain-map> </bean>
你可能注意到FilterSecurityInterceptor声明的不一样方式。命名空间元素filter-chain-map被用来设置安全过滤器链。它映射一个特定的URL模式,到过滤器链中,从bean名称来定义的filters元素。它同时支持正则表达式和ant路径,而且只使用第一个出现的匹配URI。在运行阶段FilterChainProxy会定位当前web请求匹配的第一个URI模式,由filters属性指定的过滤器bean列表将开始处理请求。过滤器会按照定义的顺序依次执行,因此你能够对处理特定URL的过滤器链进行彻底的控制。 安全
你可能注意到了,咱们在过滤器链里声明了两个SecurityContextPersistenceFilter(ASC是allowSessionCreation的简写,是SecurityContextPersistenceFilter的一个属性)。由于web服务历来不会在请求里带上jsessionid,为每一个用户代理都建立一个HttpSession彻底是一种浪费。若是你须要构建一个高等级最高可扩展性的系统,咱们推荐你使用上面的配置方法。对于小一点儿的项目,使用一个HttpSessionContextIntegrationFilter(让它的allowSessionCreation默认为true)就足够了。 cookie
在有关声明周期的问题上,若是这些方法被FilterChainProxy本身调用,FilterChainProxy会始终根据下一层的Filter代理init(FilterConfig)和destroy()方法。这时,FilterChainProxy会保证初始化和销毁操做只会在Filter上调用一次,而无论它在过滤器链中被声明了多少次)。你控制着全部的抉择,好比这些方法是否被调用或targetFilterLifecycle初始化参数DelegatingFilterProxy。默认状况下,这个参数是false,servlet容器生命周期调用不会传播到 DelegatingFilterProxy。 session
当咱们了解如何使用命名控制配置构建web安全。咱们使用一个DelegatingFilterProxy,它的名字是“springSecurityFilterChain”。你应该如今能够看到FilterChainProxy的名字,它是由命名空间建立的。 架构
2.1. 绕过过滤器链
经过命名空间,你可使用filters = "none",来提供一个过滤器bean列表。这会朝向请求模式,使用安全过滤器链总体。注意任何匹配这个模式的路径不会有任何受权或校验的服务起做用,它们是能够自由访问的。
3. 过滤器顺序
定义在web.xml里的过滤器的顺序是很是重要的。不论你实际使用的是哪一个过滤器,<filter-mapping>的顺序应该像下面这样:
ChannelProcessingFilter,由于它可能须要重定向到其余协议。
ConcurrentSessionFilter,由于它不使用SecurityContextHolder功能,可是须要更新 SessionRegistry 来从主体中放映正在进行的请求。
SecurityContextPersistenceFilter,这样 SecurityContext能够在web请求的开始阶段经过 SecurityContextHolder创建,而后 SecurityContext的任何修改都会在web请求结束的时候(为下一个web请求作准备)复制到 HttpSession中。
验证执行机制 - UsernamePasswordAuthenticationFilter, CasAuthenticationFilter, BasicAuthenticationFilter 等等 - 这样 SecurityContextHolder 能够被修改,并包含一个合法的 Authentication 请求标志。
SecurityContextHolderAwareRequestFilter,若是,你使用它,把一个Spring Security提醒HttpServletRequestWrapper安装到你的servlet容器里。
RememberMeAuthenticationFilter,这样若是以前的验证执行机制没有更新 SecurityContextHolder,这个请求提供了一个可使用的remember-me服务的cookie,一个对应的已保存的 Authentication对象会被建立出来。
AnonymousAuthenticationFilter,这样若是以前的验证执行机制没有更新 SecurityContextHolder,会建立一个匿名 Authentication对象。
ExceptionTranslationFilter,用来捕捉 Spring Security异常,这样,可能返回一个HTTP错误响应,或者执行一个对应的 AuthenticationEntryPoint。
FilterSecurityInterceptor,保护web URI。
4. 使用其余过滤器 —— 基于框架
若是你在使用SiteMesh,确认Spring Security过滤器在SiteMesh过滤器以前调用。这能够保证SecurityContextHolder为每一个SiteMesh渲染器及时建立。
5. 其余配置例子
方法一:
web.xml配置一个
<filter>
<filter-name>DelegatingFilterProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>myFilter</param-value> //本身过滤器的名字
</init-param>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DelegatingFilterProxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
方法二:
web.xml配置一个
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
方法一或者二不一样的地方就是在web.xml中的写法不一样而已没有太大的区别,配完web.xml以后还要配置applicationContext.xml中的bean。 applicationContext.xml配置: <bean id="myFilter" class="com.bjtu.filter"> //指名具体的filter类 <property name="service"> //须要注入的具体参数 <ref bean="service"/> </property> </bean> <bean id="service" parent="baseTransactionProxy">//这里的service封装了全部对数据库的操做 <property name="target"> <bean class="com.maimaiche.service.MaiMaiCheServiceImpl"> ...... </bean> </property> </bean>