安全過濾器鏈
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>