轉至:Elim的博客http://elim.iteye.com/blog/2161648html
DelegationFilterProxy不是spring security的入口,它實際上是spring的一個代理類(org.springframework.web.filter.DelegatingFilterProxy),做用是將spring 與 spring security融合。
它內部代理的是spring scurity的FilterChainProxy(org.springframework.security.web.FilterChainProxy)代理類。真正執行工做的是是FilterChainProxy。FilterChainProxy中會加載
全部的spring security filter,而後調用每一個Filter的doFilter方法。targetFilterLifecycle初始化爲true時,會調用全部filer的init初始化方法
詳情查看https://www.cnblogs.com/hzhuxin/archive/2011/12/19/2293730.htmlweb
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> <!-- 默認是false --> </init-param> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Spring security容許咱們在配置文件中配置多個http元素,以針對不一樣形式的URL使用不一樣的安全控制。Spring Security將會爲每個http元素建立對應的FilterChain,同時按照它們的聲明順序加入到FilterChainProxy。因此當咱們同時定義多個http元素時要確保將更具備特性的URL配置在前。spring
<security:http pattern="/login*.jsp*" security="none"/> <!-- http元素的pattern屬性指定當前的http對應的FilterChain將匹配哪些URL,如未指定將匹配全部的請求 --> <security:http pattern="/admin/**"> <security:intercept-url pattern="/**" access="ROLE_ADMIN"/> </security:http> <security:http> <security:intercept-url pattern="/**" access="ROLE_USER"/> </security:http>
須要注意的是http擁有一個匹配URL的pattern,未指定時表示匹配全部的請求,其下的子元素intercept-url也有一個匹配URL的pattern,該pattern是在http元素對應pattern基礎上的,也就是說一個請求必須先知足http對應的pattern纔有可能知足其下intercept-url對應的pattern。api
ChannelProcessingFilter,若是你訪問的channel錯了,那首先就會在channel之間進行跳轉,如http變爲https。安全
SecurityContextPersistenceFilter,這樣的話在一開始進行request的時候就能夠在SecurityContextHolder中創建一個SecurityContext,而後在請求結束的時候,任何對SecurityContext的改變均可以被copy到HttpSession。cookie
ConcurrentSessionFilter,由於它須要使用SecurityContextHolder的功能,並且更新對應session的最後更新時間,以及經過SessionRegistry獲取當前的SessionInformation以檢查當前的session是否已通過期,過時則會調用LogoutHandler。session
認證處理機制,如UsernamePasswordAuthenticationFilter,CasAuthenticationFilter,BasicAuthenticationFilter等,以致於SecurityContextHolder能夠被更新爲包含一個有效的Authentication請求。app
SecurityContextHolderAwareRequestFilter,它將會把HttpServletRequest封裝成一個繼承自HttpServletRequestWrapper的SecurityContextHolderAwareRequestWrapper,同時使用SecurityContext實現了HttpServletRequest中與安全相關的方法。jsp
JaasApiIntegrationFilter,若是SecurityContextHolder中擁有的Authentication是一個JaasAuthenticationToken,那麼該Filter將使用包含在JaasAuthenticationToken中的Subject繼續執行FilterChain。ui
RememberMeAuthenticationFilter,若是以前的認證處理機制沒有更新SecurityContextHolder,而且用戶請求包含了一個Remember-Me對應的cookie,那麼一個對應的Authentication將會設給SecurityContextHolder。
AnonymousAuthenticationFilter,若是以前的認證機制都沒有更新SecurityContextHolder擁有的Authentication,那麼一個AnonymousAuthenticationToken將會設給SecurityContextHolder。
ExceptionTransactionFilter,用於處理在FilterChain範圍內拋出的AccessDeniedException和AuthenticationException,並把它們轉換爲對應的Http錯誤碼返回或者對應的頁面。
FilterSecurityInterceptor,保護Web URI,而且在訪問被拒絕時拋出異常。
使用NameSpace時添加Filter到FilterChain是經過http元素下的custom-filter元素來定義的。定義custom-filter時須要咱們經過ref屬性指定其對應關聯的是哪一個Filter,此外還須要經過position、before或者after指定該Filter放置的位置。eg:position=」CAS_FILTER」就表示將定義的Filter放在CAS_FILTER對應的那個位置
別名 | Filter類 | 對應元素或屬性 |
---|---|---|
CHANNEL_FILTER | ChannelProcessingFilter | http/intercept-url@requires-channe |
SECURITY_CONTEXT_FILTER | SecurityContextPersistenceFilter | http |
CONCURRENT_SESSION_FILTER | ConcurrentSessionFilter | http/session-management/concurrency-control |
LOGOUT_FILTER | LogoutFilter | http/logout |
X509_FILTER | X509AuthenticationFilter | http/x509 |
PRE_AUTH_FILTER | AstractPreAuthenticatedProcessingFilter 的子類 | 無 |
CAS_FILTER | CasAuthenticationFilter | 無 |
FORM_LOGIN_FILTER | UsernamePasswordAuthenticationFilter | http/form-login |
BASIC_AUTH_FILTER | BasicAuthenticationFilter | http/http-basic |
SERVLET_API_SUPPORT_FILTER | SecurityContextHolderAwareRequestFilter | http@servlet-api-provision |
JAAS_API_SUPPORT_FILTER | JaasApiIntegrationFilter | http@jaas-api-provision |
REMEMBER_ME_FILTER | RememberMeAuthenticationFilter | http/remember-me |
ANONYMOUS_FILTER | AnonymousAuthenticationFilter | http/anonymous |
SESSION_MANAGEMENT_FILTER | SessionManagementFilter | http/session-managemen |
EXCEPTION_TRANSLATION_FILTER | ExceptionTranslationFilter | http |
FILTER_SECURITY_INTERCEPTOR | FilterSecurityInterceptor | http |
SWITCH_USER_FILTER | SwitchUserFilter | 無 |
FilterSecurityInterceptor是用於保護Http資源的,它須要一個AccessDecisionManager和一個AuthenticationManager的引用。它會從SecurityContextHolder獲取Authentication,而後經過SecurityMetadataSource能夠得知當前請求是否在請求受保護的資源。對於請求那些受保護的資源,若是Authentication.isAuthenticated()返回false或者FilterSecurityInterceptor的alwaysReauthenticate屬性爲true,那麼將會使用其引用的AuthenticationManager再認證一次,認證以後再使用認證後的Authentication替換SecurityContextHolder中擁有的那個。而後就是利用AccessDecisionManager進行權限的檢查。
咱們在使用基於NameSpace的配置時所配置的intercept-url就會跟FilterChain內部的FilterSecurityInterceptor綁定。若是要本身定義FilterSecurityInterceptor對應的bean,那麼該bean定義大體以下所示:
<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager" /> <property name="accessDecisionManager" ref="accessDecisionManager" /> <property name="securityMetadataSource"> <security:filter-security-metadata-source> <security:intercept-url pattern="/admin/**" access="ROLE_ADMIN" /> <security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN" /> </security:filter-security-metadata-source> </property> </bean>
filter-security-metadata-source用於配置其securityMetadataSource屬性。intercept-url用於配置須要攔截的URL與對應的權限關係。
經過前面的介紹咱們知道在Spring Security的Filter鏈表中ExceptionTranslationFilter就放在FilterSecurityInterceptor的前面。而ExceptionTranslationFilter是捕獲來自FilterChain的異常,並對這些異常作處理。ExceptionTranslationFilter可以捕獲來自FilterChain全部的異常,可是它只會處理兩類異常,AuthenticationException和AccessDeniedException,其它的異常它會繼續拋出。若是捕獲到的是AuthenticationException,那麼將會使用其對應的AuthenticationEntryPoint的commence()處理。若是捕獲的異常是一個AccessDeniedException,那麼將視當前訪問的用戶是否已經登陸認證作不一樣的處理,若是未登陸,則會使用關聯的AuthenticationEntryPoint的commence()方法進行處理,不然將使用關聯的AccessDeniedHandler的handle()方法進行處理。
AuthenticationEntryPoint是在用戶沒有登陸時用於引導用戶進行登陸認證的,在實際應用中應根據具體的認證機制選擇對應的AuthenticationEntryPoint。
AccessDeniedHandler用於在用戶已經登陸了,可是訪問了其自身沒有權限的資源時作出對應的處理。ExceptionTranslationFilter擁有的AccessDeniedHandler默認是AccessDeniedHandlerImpl,其會返回一個403錯誤碼到客戶端。咱們能夠經過顯示的配置AccessDeniedHandlerImpl,同時給其指定一個errorPage使其能夠返回對應的錯誤頁面。固然咱們也能夠實現本身的AccessDeniedHandler。
<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter"> <property name="authenticationEntryPoint"> <bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <property name="loginFormUrl" value="/login.jsp" /> </bean> </property> <property name="accessDeniedHandler"> <bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> <property name="errorPage" value="/access_denied.jsp" /> </bean> </property> </bean>
在上述配置中咱們指定了AccessDeniedHandler爲AccessDeniedHandlerImpl,同時爲其指定了errorPage,這樣發生AccessDeniedException後將轉到對應的errorPage上。指定了AuthenticationEntryPoint爲使用表單登陸的LoginUrlAuthenticationEntryPoint。此外,須要注意的是若是該filter是做爲自定義filter加入到由NameSpace自動創建的FilterChain中時需把它放在內置的ExceptionTranslationFilter後面,不然異常都將被內置的ExceptionTranslationFilter所捕獲。