本篇內(nèi)容介紹了“SecurityFilterChain的構(gòu)建過程是怎樣的”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)公司2013年至今,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都做網(wǎng)站、成都網(wǎng)站設(shè)計網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元鎮(zhèn)坪做網(wǎng)站,已為上家服務(wù),為鎮(zhèn)坪各地企業(yè)和個人服務(wù),聯(lián)系電話:028-86922220
Spring Security嵌入Servlet的核心Bean為一個名稱為 springSecurityFilterChain 的過濾器。該過濾器是Spring Security的核心入口。
無論何種方式的Web應(yīng)用,Spring Security都是從IOC中獲取“springSecurityFilterChain”的,這個Bean的注冊入口只有一個,在類WebSecurityConfiguration中,該配置對象由注解@EnableWebSecurity開啟
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public Filter springSecurityFilterChain() throws Exception { ... return webSecurity.build(); }
建造者模式:WebSecurity,建造的產(chǎn)品為:Filter,具體類型為FilterChainProxy
public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder<Filter>, ApplicationContextAware {...}
模板方法模式:AbstractConfiguredSecurityBuilder,模板方法為建造者的build方法,模板化之后調(diào)用doBuild方法,doBuild仍然是一個模板方法
@Override protected final O doBuild() throws Exception { synchronized (configurers) { buildState = BuildState.INITIALIZING; // ----- 初始化 ----- beforeInit(); init(); buildState = BuildState.CONFIGURING; // ----- 配置屬性 ----- beforeConfigure(); configure(); buildState = BuildState.BUILDING; // ----- 建造產(chǎn)品 ----- O result = performBuild(); buildState = BuildState.BUILT; return result; } }
核心構(gòu)建方法 performBuild 方法在子類中具體實(shí)現(xiàn),此處構(gòu)建類為WebSecurity
@Override protected Filter performBuild() throws Exception { // 鏈長度 int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size(); // SecurityFilterChain的構(gòu)建 List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize); // 第一部分:來自不需要安全保護(hù)請求:ignoredRequest for (RequestMatcher ignoredRequest : ignoredRequests) { securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest)); } // 第二部分:來自需要安全保護(hù)請求:securityFilterChainBuilders for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) { securityFilterChains.add(securityFilterChainBuilder.build()); } // 構(gòu)建代理類 FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains); // 防火墻 if (httpFirewall != null) { filterChainProxy.setFirewall(httpFirewall); } filterChainProxy.afterPropertiesSet(); Filter result = filterChainProxy; // 后置處理 postBuildAction.run(); // 構(gòu)建完畢 return result; }
第一篇文章也說了,F(xiàn)ilterChainProxy代理的多條SecurityFilterChain最終只能走一條,因此SecurityFilterChain來源十分重要,上面的代碼說明來源是2部分,這兩部分都是WebSecurity的私有屬性,也就是可以在任何可以獲得WebSecurity實(shí)例的位置進(jìn)行配置,但是一般都會按照規(guī)約進(jìn)行,防止代理混亂、不易讀。以下WebSecurity的2個屬性分別表示2種來源
private final List<RequestMatcher> ignoredRequests = new ArrayList<>(); private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<>();
這兩種來源的SecurityFilterChain其實(shí)涉及了2種構(gòu)建者:WebSecurity和HttpSecurity,前者基于Web應(yīng)用(一般就是MVC)來構(gòu)建安全,后者基于請求-響應(yīng)(一般而言就是HTTP)來構(gòu)建安全。
基于Servlet的Web應(yīng)用的安全訪問控制,Spring Security與Spring MVC緊密集成。在WebSecurity可以進(jìn)行整體的配置,優(yōu)先級最高
WebSecurity內(nèi)部類IgnoredRequestConfigurer提供了配置ignoredRequests的功能,并且提供了mvcMatchers(String... mvcPatterns)和mvcMatchers(HttpMethod method,String... mvcPatterns)兩種配置入口。通過WebSecurity#ignoring方法就能拿到該對象實(shí)例并完成配置:該配置符合鏈?zhǔn)秸{(diào)用,每個IgnoredRequestConfigurer都可以構(gòu)建一條SecurityFilterChain
@Override public void configure(WebSecurity web) throws Exception { super.configure(web); // 獲取IgnoredRequest配置對象 web.ignoring() // 鏈?zhǔn)秸{(diào)用 .mvcMatchers("/login") // 鏈?zhǔn)秸{(diào)用 .mvcMatchers("/home") ; }
基于網(wǎng)絡(luò)請求的安全訪問控制,在Servlet中網(wǎng)絡(luò)請求主要在Filter中,這部分主要是配置的Http請求流轉(zhuǎn)過程中的安全。
大部分開發(fā)使用的就是這種來源,每個實(shí)例構(gòu)建一條SecurityFilterChain。WebSecurity提供了addSecurityFilterChainBuilder方法來配置,因此通過WebSecurity實(shí)例也能完成配置,但是securityFilterChainBuilder構(gòu)建流程復(fù)雜,一般都使用Spring Security提供的內(nèi)置方法來簡化這個流程,例如在WebSecurityConfigurerAdapter#init中就默認(rèn)調(diào)用了addSecurityFilterChainBuilder(HttpSecurity)
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); }
針對方法級別的攔截:區(qū)分為前置攔截:beforeInvocation和后置攔截:afterInvocation,前后攔截原理基本一致。
這是開發(fā)者經(jīng)常接觸方式,這種模式引入一個專有名詞:ConfigAttribute,直譯:屬性配置,但是對于開發(fā)而已可以稱為:安全訪問規(guī)則。
可以對任何路徑配置(每個Controller方法其實(shí)對應(yīng)的就是訪問路徑)安全訪問規(guī)則。權(quán)限標(biāo)識屬于一種安全訪問規(guī)則。
對安全訪問規(guī)則ConfigAttribute能否滿足訪問資源的權(quán)限的決斷,由AccessDecisionManager處理,AccessDecisionManager特定訪問規(guī)則的web資源能否被訪問。
而AccessDecisionManager做出決斷需要當(dāng)前賬號的認(rèn)證信息,因此在做出決斷之前會嘗試通過AuthenticationManager獲取當(dāng)前請求的身份認(rèn)證信息。
這里獲取認(rèn)證信息、做出訪問決斷是Spring Security的另一個核心,會單獨(dú)說明,本篇文章主要描述SecurityFilterChain的構(gòu)建。
功能:配置基于請求路徑的安全訪問規(guī)則:ConfigAttribute
HttpSecurity主要配置Filter鏈,也就是SecurityFilterChain的來源,也是最常見的,當(dāng)然也是最重要的,下面為默認(rèn)的配置
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,sharedObjects); if (!disableDefaults) { // @formatter:off http .csrf().and() .addFilter(new WebAsyncManagerIntegrationFilter()) .exceptionHandling().and() .headers().and() .sessionManagement().and() .securityContext().and() .requestCache().and() .anonymous().and() .servletApi().and() .apply(new DefaultLoginPageConfigurer<>()).and() .logout(); // @formatter:on ClassLoader classLoader = this.context.getClassLoader(); // 拿出IOC容器中所有AbstractHttpConfigurer具體類,逐個配置 List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader); for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) { http.apply(configurer); } } // 常見的配置方法:protected void configure(HttpSecurity http) throws Exception { configure(http);
這里默認(rèn)會加入10個Configurer,每個對應(yīng)一個Filter,defaultHttpConfigurers默認(rèn)為空,可以自定義Bean來注冊,會覆蓋默認(rèn)配置,再加上配置的WebAsyncManagerIntegrationFilter和平時常用的formLogin總共12個Filter,各種Filter之間時有序的。
configure(http);方法則是開發(fā)者重寫的方法,用于擴(kuò)展SecurityFilterChain中的Filter,同樣此處定義會覆蓋前面默認(rèn)配置,每種configurer都與對應(yīng)一種Filter
功能:配置Web請求通道轉(zhuǎn)換后重定向,默認(rèn)兩種:安全的https->443、不安全的http->80,不區(qū)分的權(quán)限標(biāo)識為:"ANY_CHANNEL"。如果不需要https保護(hù)接口,則不用配置該過濾器。
功能:將SecurityContext配置到異步請求WebAsyncManager中,MVC支持異步Controller,返回對象為:DeferredResult等
功能:對于session存在的請求,驗(yàn)證session是否過期,如果過期,則調(diào)用doLogout方法,否則更新session的訪問時間。默認(rèn)不啟用該Filter,可以在sessionManagement#maximumSessions控制。
功能:持久化SecurityContext,即Security上下文,使得能從線程中獲取到當(dāng)前登錄用戶的信息,持久化方式默認(rèn)是HttpSessionSecurityContextRepository即服務(wù)器Session,key="SPRING_SECURITY_CONTEXT"。
功能:在請求響應(yīng)的頭部添加自定義信息
功能:跨域處理,注意這個過濾器是Spring Security內(nèi)部過濾器,在優(yōu)先級更高過濾器中就返回的響應(yīng)不會具有跨域能力
功能:跨站請求攻擊防御,默認(rèn)對"GET", "HEAD", "TRACE", "OPTIONS"請求進(jìn)行CSRF保護(hù),默認(rèn)為session中保存CsrfToken,前后端進(jìn)行驗(yàn)證
功能:匹配路徑登出
功能:使用賬號、密碼模式的UsernamePasswordAuthenticationToken身份認(rèn)證
功能: 在未指定登錄登出頁面時,生成默認(rèn)的頁面
功能:通過UsernamePasswordAuthenticationToken處理請求頭中Basic格式的Authorization認(rèn)證信息
功能:用來恢復(fù)登錄流程中被中斷(認(rèn)證失?。┑恼埱?。
在RequestCacheConfigurer中對HttpRequest緩存條件加了以下默認(rèn)限制
Csrf開啟時:只能為GET請求
不緩存網(wǎng)站圖標(biāo)請求:即路徑不能匹配“/**/favicon.*”
不緩存這三種媒體類型MediaType:"application/json"、"multipart/form-data"、"text/event-stream"
不緩存xjax請求,即請求頭"X-Requested-With"不能為:"XMLHttpRequest"
功能:實(shí)現(xiàn)Servlet3 API接口,主要在SecurityContextHolderAwareRequestWrapper重寫實(shí)現(xiàn),例如getRemoteUser、getUserPrincipal、isUserInRole
功能:當(dāng)用戶沒有登錄而訪問web資源時,可以從cookie或者內(nèi)存中找出身份識別信息從而靜默登錄
功能:當(dāng)Security Context中認(rèn)證信息為null時設(shè)置Security Context=AnonymousAuthenticationToken,默認(rèn)權(quán)限為"ROLE_ANONYMOUS"
功能:針對未持久化過SecurityContext的請求進(jìn)行session會話固定(Session fixation)保護(hù)和限制用戶打開會話數(shù)量。
功能:處理Spring Security流程中出現(xiàn)的異常,主要就是AuthenticationException和AccessDeniedException異常,獲取到異常一般都會交給對應(yīng)的AuthenticationEntryPoint#commence去處理,但是非AnonymousAuthenticationToken或者RememberMeAuthenticationToken產(chǎn)生的AccessDeniedException會交給過濾器中的accessDeniedHandler來處理(例如:403)
過濾器有排序的,整體排序如下
FilterComparator() { Step order = new Step(INITIAL_ORDER, ORDER_STEP); put(ChannelProcessingFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); put(WebAsyncManagerIntegrationFilter.class, order.next()); put(SecurityContextPersistenceFilter.class, order.next()); put(HeaderWriterFilter.class, order.next()); put(CorsFilter.class, order.next()); put(CsrfFilter.class, order.next()); put(LogoutFilter.class, order.next()); filterToOrder.put("org.springframework.security.oauth3.client.web.OAuth3AuthorizationRequestRedirectFilter",order.next()); filterToOrder.put("org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter",order.next()); put(X509AuthenticationFilter.class, order.next()); put(AbstractPreAuthenticatedProcessingFilter.class, order.next()); filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",order.next()); filterToOrder.put("org.springframework.security.oauth3.client.web.OAuth3LoginAuthenticationFilter",order.next()); filterToOrder.put("org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter",order.next()); put(UsernamePasswordAuthenticationFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); filterToOrder.put("org.springframework.security.openid.OpenIDAuthenticationFilter", order.next()); put(DefaultLoginPageGeneratingFilter.class, order.next()); put(DefaultLogoutPageGeneratingFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); put(DigestAuthenticationFilter.class, order.next()); filterToOrder.put("org.springframework.security.oauth3.server.resource.web.BearerTokenAuthenticationFilter", order.next()); put(BasicAuthenticationFilter.class, order.next()); put(RequestCacheAwareFilter.class, order.next()); put(SecurityContextHolderAwareRequestFilter.class, order.next()); put(JaasApiIntegrationFilter.class, order.next()); put(RememberMeAuthenticationFilter.class, order.next()); put(AnonymousAuthenticationFilter.class, order.next()); filterToOrder.put("org.springframework.security.oauth3.client.web.OAuth3AuthorizationCodeGrantFilter",order.next()); put(SessionManagementFilter.class, order.next()); put(ExceptionTranslationFilter.class, order.next()); put(FilterSecurityInterceptor.class, order.next()); put(SwitchUserFilter.class, order.next()); }
注意排序中FilterSecurityInterceptor的優(yōu)先級別很低,防御的是Web中方法級別的安全。最終SecurityFilterChain來源如圖示下
“SecurityFilterChain的構(gòu)建過程是怎樣的”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
分享名稱:SecurityFilterChain的構(gòu)建過程是怎樣的
網(wǎng)頁網(wǎng)址:http://sd-ha.com/article14/ieccde.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、網(wǎng)站內(nèi)鏈、品牌網(wǎng)站制作、電子商務(wù)、網(wǎng)站設(shè)計、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)