天天看點

spring DelegatingFilterProxy管理過濾器

安全過濾器鍊 

Spring Security的web架構是完全基于标準的servlet過濾器的。它沒有在内部使用servlet或任何其他基于servlet的架構(比如spring mvc),是以它沒有與任何特定的web技術強行關聯。 它隻管處理HttpServletRequest和HttpServletResponse,不關心請求時來自浏覽器,web服務用戶端,HttpInvoker還是一個AJAX應用。 

Spring Security維護了一個過濾器鍊,每個過濾器擁有特定的功能,過濾器需要服務也會對應添加和删除。過濾器的次序是非常重要的,它們之間都有依賴關系。 如果你已經使用了命名空間配置,過濾器會自動幫你配置, 你不需要定義任何SpringBean,但是有時候你需要完全控制Spring過濾器鍊,因為你使用了命名空間沒有提供的特性,或者你需要使用你自己自定義的類。 

1. DelegatingFilterProxy 

當使用servlet過濾器時,你很需要在你的web.xml中聲明它們, 它們可能被servlet容器忽略。在SpringSecurity,過濾器類也是定義在xml中的spring bean, 是以可以獲得Spring的依賴注入機制和生命周期接口。spring的DelegatingFilterProxy提供了在 web.xml和applicationcontext之間的聯系。 

當使用DelegatingFilterProxy,你會看到像web.xml檔案中的這樣内容: 

myFilter org.springframework.web.filter.DelegatingFilterProxy myFilter /*  

注意這個過濾器其實是一個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中聲明的。這裡有一個例子: 

<sec:filter-chain-mappath-type="ant"><sec:filter-chainpattern=" ebservices="" *"="" filters="securityContextPersistenceFilterWithASCFalse,basicAuthenticationFilter, exceptionTranslationFilter,filterSecurityInterceptor"> 

你可能注意到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)就足夠了。 

在有關聲明周期的問題上,如果這些方法被FilterChainProxy自己調用,FilterChainProxy會始終根據下一層的Filter代理init(FilterConfig)和destroy()方法。這時,FilterChainProxy會保證初始化和銷毀操作隻會在Filter上調用一次,而不管它在過濾器鍊中被聲明了多少次)。你控制着所有的抉擇,比如這些方法是否被調用或targetFilterLifecycle初始化參數DelegatingFilterProxy。預設情況下,這個參數是false,servlet容器生命周期調用不會傳播到DelegatingFilterProxy。 

當我們了解如何使用命名控制配置建構web安全。我們使用一個DelegatingFilterProxy,它的名字是“springSecurityFilterChain”。你應該現在可以看到FilterChainProxy的名字,它是由命名空間建立的。 

2.1. 繞過過濾器鍊 

通過命名空間,你可以使用filters = "none",來提供一個過濾器bean清單。這會朝向請求模式,使用安全過濾器鍊整體。注意任何比對這個模式的路徑不會有任何授權或校驗的服務起作用,它們是可以自由通路的。 

3. 過濾器順序 

定義在web.xml裡的過濾器的順序是非常重要的。不論你實際使用的是哪個過濾器, 的順序應該像下面這樣:  

ChannelProcessingFilter,因為它可能需要重定向到其他協定。  

ConcurrentSessionFilter,因為它不使用SecurityContextHolder功能,但是需要更新SessionRegistry 來從主體中放映正在進行的請求。  

SecurityContextPersistenceFilter,這樣 SecurityContext可以在web請求的開始階段通過SecurityContextHolder建立,然後SecurityContext的任何修改都會在web請求結束的時候(為下一個web請求做準備)複制到HttpSession中。  

驗證執行機制 - UsernamePasswordAuthenticationFilter,CasAuthenticationFilter, BasicAuthenticationFilter 等等 - 這樣SecurityContextHolder 可以被修改,并包含一個合法的 Authentication請求标志。  

SecurityContextHolderAwareRequestFilter,如果,你使用它,把一個SpringSecurity提醒HttpServletRequestWrapper安裝到你的servlet容器裡。  

RememberMeAuthenticationFilter,這樣如果之前的驗證執行機制沒有更新SecurityContextHolder,這個請求提供了一個可以使用的remember-me服務的cookie,一個對應的已儲存的Authentication對象會被建立出來。  

AnonymousAuthenticationFilter,這樣如果之前的驗證執行機制沒有更新SecurityContextHolder,會建立一個匿名Authentication對象。  

ExceptionTranslationFilter,用來捕捉 SpringSecurity異常,這樣,可能傳回一個HTTP錯誤響應,或者執行一個對應的AuthenticationEntryPoint。  

FilterSecurityInterceptor,保護web URI。  

4. 使用其他過濾器 —— 基于架構  

如果你在使用SiteMesh,确認Spring Security過濾器在SiteMesh過濾器之前調用。這可以保證SecurityContextHolder為每個SiteMesh渲染器及時建立。  

5. 其他配置例子  

方法一:  

web.xml配置一個  

DelegatingFilterProxy   

org.springframework.web.filter.DelegatingFilterProxy   

targetBeanName   

myFilter  //自己過濾器的名字  

targetFilterLifecycle   

true   

/*   

方法二:  

myFilter   

方法一或者二不同的地方就是在web.xml中的寫法不同而已沒有太大的差別,配完web.xml之後還要配置applicationContext.xml中的bean。  

applicationContext.xml配置:  

//指名具體的filter類  

<propertyname="service"> //需要注入的具體參數  

<refbean="service">  

//這裡的service封裝了所有對資料庫的操作  

<propertyname="target">  

<beanclass="com.maimaiche.service.maimaicheserviceimpl">  

......  

--------------------------------------------------  

1、web.xml  

14379709.67309

appFilters  

class >org.springframework.web.filter.DelegatingFilterProxy class> 

targetFilterLifecycle  

true  

/*  

2、applicationContext-filter.xml  

"appFilters" class = "org.springframework.security.util.FilterChainProxy" > 

"ant" > 

"characterEncodingFilter,commonParamsFilter"

pattern="/**"/> 

"characterEncodingFilter" class="org.springframework.web.filter.CharacterEncodingFilter"> 

"encoding" value="UTF-8"/> 

"forceEncoding" value="true"/> 

"commonParamsFilter" class="com.renren.wap.fuxi.filter.CommonParamsFilter"/>

本文轉自二郎三郎部落格園部落格,原文連結:http://www.cnblogs.com/haore147/p/5213619.html,如需轉載請自行聯系原作者