Spring Security 實戰(zhàn)干貨:WebSecurity和HttpSecurity的關(guān)系
前幾天有粉絲私信我:WebSecurity和HttpSecurity啥關(guān)系?當時給我問住了,我大概只知道它們之間的關(guān)系類似TypeScript和JavaScript的關(guān)系,但是具體的細節(jié)確實不太清楚。因此就在周末簡單研究了一下。
HttpSecurity的本質(zhì)
前幾天在Spring Security 5.4的新玩法中介紹了一種新的配置HttpSecurity的方式:
- @Bean
- SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- return http
- .antMatcher("/**")
- .authorizeRequests(authorize -> authorize
- .anyRequest().authenticated()
- )
- .build();
- }
其實就能夠知道HttpSecurity是用來構(gòu)建包含了一系列過濾器鏈的過濾器SecurityFilterChain,平常我們的配置就是圍繞構(gòu)建SecurityFilterChain進行。還得拿出這張老圖:
安全過濾鏈
從上面這個圖中可以看出構(gòu)建好的還要交給FilterChainProxy來代理,是不是有點多此一舉?
WebSecurity的本質(zhì)
在有些情況下這種確實多此一舉, 不過更多時候我們可能需要配置多個SecurityFilterChain來實現(xiàn)對多種訪問控制策略。
多個SecurityFilterChain
為了精細化的管理多個SecurityFilterChain的生命周期,搞一個統(tǒng)一管理這些SecurityFilterChain的代理就十分必要了,這就是WebSecurity的意義。下面是WebSecurity的build方法的底層邏輯:
- @Override
- protected Filter performBuild() throws Exception {
- Assert.state(!this.securityFilterChainBuilders.isEmpty(),
- () -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
- + "Typically this is done by exposing a SecurityFilterChain bean "
- + "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
- + "More advanced users can invoke " + WebSecurity.class.getSimpleName()
- + ".addSecurityFilterChainBuilder directly");
- // 被忽略請求的個數(shù) 和 httpscurity的個數(shù) 構(gòu)成了過濾器鏈集合的大小
- int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
- List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
- // 初始化過濾器鏈集合中的 忽略請求過濾器鏈
- for (RequestMatcher ignoredRequest : this.ignoredRequests) {
- securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
- }
- // 初始化過濾器鏈集合中的 httpsecurity定義的過濾器鏈
- for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
- securityFilterChains.add(securityFilterChainBuilder.build());
- }
- FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
- if (this.httpFirewall != null) {
- // 請求防火墻
- filterChainProxy.setFirewall(this.httpFirewall);
- }
- if (this.requestRejectedHandler != null) {
- // 請求拒絕處理器
- filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
- }
- filterChainProxy.afterPropertiesSet();
- Filter result = filterChainProxy;
- if (this.debugEnabled) {
- this.logger.warn("\n\n" + "********************************************************************\n"
- + "********** Security debugging is enabled. *************\n"
- + "********** This may include sensitive information. *************\n"
- + "********** Do not use in a production system! *************\n"
- + "********************************************************************\n\n");
- result = new DebugFilter(filterChainProxy);
- }
- this.postBuildAction.run();
- return result;
- }
從上面中的源碼可以看出,WebSecurity用來構(gòu)建一個名為springSecurityFilterChain的Spring BeanFilterChainProxy 。它的作用是來定義那些請求忽略安全控制,那些請求必須安全控制,在合適的時候清除SecurityContext以避免內(nèi)存泄漏,同時也可以用來定義請求防火墻和請求拒絕處理器,另外我們開啟Spring Seuciry Debug模式也是這里配置的。
同時還有一個作用可能是其它文章沒有提及的,F(xiàn)ilterChainProxy是Spring Security對Spring framework應(yīng)用的唯一出口,然后通過它與一個Servlet在Spring的橋接代理DelegatingFilterProxy結(jié)合構(gòu)成Spring對Servlet體系的唯一出口。這樣就將Spring Security、Spring framework、Servlet API三者隔離了起來。
總結(jié)
我們事實上可以認為,WebSecurity是Spring Security對外的唯一出口,而HttpSecurity只是內(nèi)部安全策略的定義方式;WebSecurity對標FilterChainProxy,而HttpSecurity則對標SecurityFilterChain,另外它們的父類都是AbstractConfiguredSecurityBuilder。掌握了這些基本上你就能知道它們之間的區(qū)別是什么了。
本文轉(zhuǎn)載自微信公眾號「碼農(nóng)小胖哥」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系碼農(nóng)小胖哥公眾號。