SpringSecurity 初始化流程源碼
本篇主要講解 SpringSecurity初始化流程的源碼部分,包括核心的 springSecurityFilterChain 是如何創建的,以及在介紹哪裡可以擴展個性化的配置,SpringSecurity源碼其實是蠻難得 各種Builder Configure 看得真的頭疼!
1.簡單介紹
SpringSecurity 的核心功能主要包括:
認證 (你是誰) 授權 (你能幹什麼) 攻擊防護 (防止偽造身份)
其核心就是一組過濾器鏈,項目啟動後將會自動配置,本篇也會涉及過濾器鏈是如何自動初始化的。
SecurityContextPersistenceFilter 是最前面的一個filter 請求到它時候會去檢查 根據sessionId找到session 判斷session 中是否存在 SecurityContext 在 則將 SecurityContext 存入當前的線程中去 響應的時候,看當前線程是否有SecurityContext ,如果有 放入到session中去 這樣不同的請求都能拿到相同的 用戶認證信息。
UsernamePasswordAuthenticationFilter 該過濾器是處理表單登錄的,通過表單登錄提交的認證都會經過它處理
SocialAuthenticationFilter 比如這個就是社交登錄使用的Filter 詳細可以看我另外一篇 SpringSocial 實現第三方QQ登錄
https://www.askajohnny.com/#/blog/123
綠色的過濾器都是可配置的,其他顏色的都不行!
2.SecurityAutoConfiguration
如果是SpringBoot項目只要你依賴了SpringSecurity相關依賴依然會有自動配置類
SecurityAutoConfiguration 生效 它會導入WebSecurityEnableConfiguration
@EnableWebSecurity將會是我們本篇的主要切入點
3.@EnableWebSecurity註解介紹
該註解 它是初始化Spring Security的入口 .
打開@EnableWebSecurity註解
<code>@Retention
(value = java.lang.annotation.RetentionPolicy.RUNTIME)@Target
(value = { java.lang.annotation.ElementType.TYPE })@Documented
@Import
({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class })@EnableGlobalAuthentication
@Configuration
public@interface
EnableWebSecurity {/<code>
<code> /** * Controls debugging supportfor
Spring Security. Default isfalse
. * @return
if
true
, enablesdebug
support with Spring Security */ booleandebug
() defaultfalse
; } /<code>
該註解類通過@Configuration和@Import配合使用引入了一個配置類(WebSecurityConfiguration)和兩個ImportSelector(
SpringWebMvcImportSelector,OAuth2ImportSelector),我們重點關注下WebSecurityConfiguration,它是Spring Security的核心
4.springSecurityFilterChain初始化流程及源碼
打開WebSecurityConfiguration 它是一個配置類,主要看 springSecurityFilterChain()方法,它就是初始化springSecurityFilterChain的核心方法
<code> (name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)public
FilterspringSecurityFilterChain
()
throws
Exception {boolean
hasConfigurers = webSecurityConfigurers !=null
&& !webSecurityConfigurers.isEmpty();if
(!hasConfigurers) { WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(new
WebSecurityConfigurerAdapter() { }); webSecurity.apply(adapter); }return
webSecurity.build(); }/<code>
@Bean註解name屬性值
AbstractSecurityWebApplicationInitializer.DEFAULTFILTERNAME就是XML中定義的springSecurityFilterChain
從源碼中知道過濾器通過最後的 webSecurity.build()創建,webSecurity的類型為:WebSecurity,它在
setFilterChainProxySecurityConfigurer方法中優先被創建了:
<code> (required =false
)public
void
setFilterChainProxySecurityConfigurer
( ObjectPostProcessor objectPostProcessor, @Value(
"#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}"
) List> webSecurityConfigurers)throws
Exception { webSecurity = objectPostProcessor .postProcess(new
WebSecurity(objectPostProcessor));if
(debugEnabled !=null
) { webSecurity.debug(debugEnabled); }/<code>
<code>webSecurityConfigurers
.sort
(AnnotationAwareOrderComparator
.INSTANCE
);/<code>
<code> Integer previousOrder =null
; Object previousConfig =null
;for
(SecurityConfigurer config : webSecurityConfigurers) { Integer order = AnnotationAwareOrderComparator.lookupOrder(config);if
(previousOrder !=null
&& previousOrder.equals
(order)) {throw
new
IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of "
+ order +" was already used on "
+ previousConfig +", so it cannot be used on "
+ config +" too."
); } previousOrder = order; previousConfig = config; }for
(SecurityConfigurer webSecurityConfigurer : webSecurityConfigurers) { webSecurity.apply(webSecurityConfigurer); }this
.webSecurityConfigurers = webSecurityConfigurers; }/<code>
從代碼中可以看到,它是直接被new出來的:
<code> webSecurity = objectPostProcessor .postProcess(new
WebSecurity(objectPostProcessor)); /<code>
setFilterChainProxySecurityConfigurer 該方法的webSecurityConfigurers 參數是通過@Value注入的
<code> @Value("
#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}
") /<code>
**
AutowiredWebSecurityConfigurersIgnoreParents的 getWebSecurityConfigurers() 如下,就是獲取所有的 WebSecurityConfigurer的類型的配置類 而通常 我們通過繼承
WebSecurityConfigurerAdapter 來自定義WebSecurityConfigurer**
<code>public
List> getWebSecurityConfigurers() { List> webSecurityConfigurers =new
ArrayList<>(); Map beansOfType = beanFactory .getBeansOfType(WebSecurityConfigurer.
class
);for
(Entry entry : beansOfType.entrySet()) { webSecurityConfigurers.add(entry.getValue()); }return
webSecurityConfigurers; } /<code>
再回到
setFilterChainProxySecurityConfigurer方法 下面有一段這樣的代碼 ,對於上面獲取的所有的WebSecurityConfigurer類型 循環執行 webSecurity的apply方法
<code>for
(SecurityConfigurerwebSecurityConfigurer
: webSecurityConfigurers) {webSecurity
.apply
(webSecurityConfigurer); } /<code>
webSecurity集成
AbstractConfiguredSecurityBuilder 它提供apply方法 再其內部調用add方法
<code>public
>C
apply
(C configurer
) throws Exception {add
(configurer);return
configurer; } /<code>
**add(configurer),主要就是將其傳入的WebSecurityConfigurer存入到 LinkedHashMap configures中,主要代碼 this.configurers.put(clazz, configs);**
<code>private
>void
add
(C configurer)
{ Assert.notNull(configurer,"configurer cannot be null"
);/<code>
<code> Class extends SecurityConfigurer> clazz = (Class extends SecurityConfigurer>) configurer .getClass(); synchronized (configurers) {if
(buildState.isConfigured()) {throw
new
IllegalStateException("Cannot apply "
+ configurer +" to already built object"
); } List> configs = allowConfigurersOfSameType ?this
.configurers .get
(clazz) :null
;if
(configs ==null
) { configs =new
ArrayList<>(1
); } configs.add
(configurer);this
.configurers.put(clazz, configs);if
(buildState.isInitializing()) {this
.configurersAddedInInitializing.add
(configurer); } } }/<code>
當所有的 WebSecurityConfigurer 類型的配置 全部應用到 WebSecurity中去後
setFilterChainProxySecurityConfigurer方法也就結束了
回到創建過濾器鏈的方法 springSecurityFilterChain()
它會判斷我們剛剛的webSecurityConfigurers是否存在,不存在就新建一個,然後執行 webSecurity.build() 重要!
<code> (name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)public
FilterspringSecurityFilterChain
()
throws
Exception {boolean
hasConfigurers = webSecurityConfigurers !=null
&& !webSecurityConfigurers.isEmpty();if
(!hasConfigurers) { WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(new
WebSecurityConfigurerAdapter() { }); webSecurity.apply(adapter); }return
webSecurity.build(); } /<code>
最終內部會有下面這段代碼, 主要關注 init() configure() 和 performBuild() 這三個方法
<code>protected
final
OdoBuild
()
throws
Exception {synchronized
(configurers) { buildState = BuildState.INITIALIZING;/<code>
<code>beforeInit
();init
();/<code>
<code>buildState
= BuildState.CONFIGURING;/<code>
<code>beforeConfigure
();configure
();/<code>
<code>buildState
= BuildState.BUILDING;/<code>
<code>O
result = performBuild();/<code>
<code>buildState
= BuildState.BUILT;/<code>
<code>return
result; } }/<code>
init() 內部循環遍歷 所有的 WebSecurityConfigurer ,它會執行到
WebSecurityConfigurerAdapter的
<code>private
void
init
()
throws
Exception { Collection> configurers = getConfigurers();/<code>
<code>for
(SecurityConfigurer configurer : configurers) { configurer.init
((B)this
); }/<code>
<code>for
(SecurityConfigurer configurer : configurersAddedInInitializing) { configurer.init
((B)this
); } }/<code>
configurer.init((B) this)
它只要完成兩件重要的事情:
初始化HttpSecurity對象(注意它和WebSecurity不一樣 );
設置HttpSecurity對象添加至WebSecurity的securityFilterChainBuilders列表中;
<code>public
void
init
(
final
WebSecurity web)throws
Exception {final
HttpSecurity http = getHttp(); web.addSecurityFilterChainBuilder(http).postBuildAction(() -> { FilterSecurityInterceptor securityInterceptor = http .getSharedObject(FilterSecurityInterceptor.
class
); web.securityInterceptor(securityInterceptor); }); } 初始化HttpSecurity對象在getHttp()方法中實現:/<code>
<code>protected
final
HttpSecuritygetHttp
()
throws
Exception {if
(http !=null
) {return
http; }/<code>
<code> DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor .postProcess(new
DefaultAuthenticationEventPublisher()); localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);/<code>
<code> AuthenticationManager authenticationManager = authenticationManager(); authenticationBuilder.parentAuthenticationManager(authenticationManager); authenticationBuilder.authenticationEventPublisher(eventPublisher);Map
,Object
> sharedObjects = createSharedObjects();/<code>
<code> 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(); List defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.
class
,classLoader
);/<code>
<code>for
(AbstractHttpConfigurerconfigurer
: defaultHttpConfigurers) {http
.apply
(configurer); } }configure
(http);return
http
; } /<code>
從代碼中可以瞭解,HttpSecurity是直接被new出來的,在創建HttpSecurity之前,首先初始化了
AuthenticationManagerBuilder對象,這裡有段代碼很重要就是: AuthenticationManager authenticationManager = authenticationManager();,它創建AuthenticationManager實例,打開authenticationManager()方法:
默認實現是在
WebSecurityConfigurerAdapter 中
<code>protected
void
configure
(AuthenticationManagerBuilder auth)
throws
Exception {this
.disableLocalConfigureAuthenticationBldr =true
; }/<code>
1、個性化配置入口之configure(
AuthenticationManagerBuilder auth)
我們可以通過繼承
WebSecurityConfigurerAdapter並重寫該方法來個性化配置
AuthenticationManagerBuilder。
如下是自己繼承
WebSecurityConfigurerAdapter 重寫 configure(
AuthenticationManagerBuilder auth),實現個性化的第一個配置入口
<code>@Configuration
@Slf4j
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter { /<code>
<code>protected
void
configure
(AuthenticationManagerBuilder auth)
throws
Exception {super
.configure(auth); log.info("【測試 定製化入口 configure(AuthenticationManagerBuilder auth) 的執行 】"
); } }/<code>
構建完HttpSecurity實例後,默認情況下會添加默認的攔截其配置:
<code>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
();/<code>
我挑一個默認的方法展開看一下比如 會話管理的sessionManagement(),內部就是去創建
SessionManagementConfigurer並應用它
<code>public
SessionManagementConfigurersessionManagement
()
throws
Exception {return
getOrApply(new
SessionManagementConfigurer<>()); }/<code>
getOrApply 最有一句代碼 return apply(configurer);
<code>private
>C
getOrApply
( C configurer)
throws
Exception { C existingConfig = (C) getConfigurer(configurer.getClass());if
(existingConfig !=null
) {return
existingConfig; }return
apply(configurer); }/<code>
apply(configurer) 注意這裡的 configurer傳入的是
SessionManagementConfigurer
<code>public
>C
apply
(C configurer
) throws Exception { configurer.addObjectPostProcessor(objectPostProcessor); configurer.setBuilder((B)this
);add
(configurer);return
configurer; }/<code>
最終又調用了 add(configurer); 這不過這裡是給 HttpSecurity的 configurers 配置初始的,上面是配置的WebSecurity的configurers, 不要混淆,最終這些configurers會被一個個創建成 對應的過濾器Filter的 詳細在後面有說明
<code>private
>void
add
(C configurer)
{ Assert.notNull(configurer,"configurer cannot be null"
);/<code>
<code> Class extends SecurityConfigurer> clazz = (Class extends SecurityConfigurer>) configurer .getClass(); synchronized (configurers) {if
(buildState.isConfigured()) {throw
new
IllegalStateException("Cannot apply "
+ configurer +" to already built object"
); } List> configs = allowConfigurersOfSameType ?this
.configurers .get
(clazz) :null
;if
(configs ==null
) { configs =new
ArrayList<>(1
); } configs.add
(configurer);this
.configurers.put(clazz, configs);if
(buildState.isInitializing()) {this
.configurersAddedInInitializing.add
(configurer); } } } 如下圖:為HttpSecurity添加了很多默認的配置 ![Xnip20200118_205631.png](http: /<code>
回到 getHttp()方法
最後調用configure(http);,這又是一個可個性化的配置入口,它的默認實現是:
WebSecurityConfigurerAdapter提供的
默認的配置是攔截所有的請求需要認證之後才能訪問,如果沒有認證,會自動生成一個認證表單要求輸入用戶名和密碼。
<code>protected
void
configure
(HttpSecurity http)
throws
Exception { logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity)."
);/<code>
<code>http
.authorizeRequests
().anyRequest
().authenticated
().and
().formLogin
().and
().httpBasic
(); }/<code>
2、個性化配置入口之configure(HttpSecurity http) 我們可以通過繼承
WebSecurityConfigurerAdapter並重寫該方法來個性化配置HttpSecurity。
OK,目前為止HttpSecurity已經被初始化,接下去需要設置HttpSecurity對象添加至WebSecurity的
securityFilterChainBuilders列表中:
<code>public
void
init
(
final
WebSecurity web)throws
Exception {final
HttpSecurity http = getHttp(); web.addSecurityFilterChainBuilder(http).postBuildAction(() -> { FilterSecurityInterceptor securityInterceptor = http .getSharedObject(FilterSecurityInterceptor.
class
); web.securityInterceptor(securityInterceptor); }); } /<code>
當所有的WebSecurityConfigurer的init方法被調用之後,webSecurity.init()工作就結束了
接下去調用了webSecurity.configure(),該方法同樣是在
AbstractConfiguredSecurityBuilder中實現的:
<code>private
void
configure
()
throws
Exception { Collection> configurers = getConfigurers();/<code>
<code>for
(SecurityConfigurerconfigurer
: configurers) {configurer
.configure
((B) this); } } /<code>
它的主要工作是迭代調用所有WebSecurityConfigurer的configurer方法,參數是WebSeucrity本身,這又是另外一個重要的個性化入口:
3、個性化配置入口之configure(WebSecurity web) 我們可以通過繼承
WebSecurityConfigurerAdapter並重寫該方法來個性化配置WebSecurity。
至此,三個重要的個性化入口都已經被調用,即在實現
WebSecurityConfigurerAdapter經常需要重寫的:
<code>1
、configure
(AuthenticationManagerBuilder auth);/<code>
<code>2
、configure
(WebSecurity web);/<code>
<code>3
、configure
(HttpSecurity http);/<code>
回到webSecurity構建過程,接下去重要的的調用:
<code>O
result = performBuild(); /<code>
performBuild() 非常重要!!
<code> @Override protected Filter performBuild() throws Exception { Assert.state( !securityFilterChainBuilders.isEmpty(),()
->"At least one SecurityBuilder extends SecurityFilterChain> needs to be specified. "
+"Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+"More advanced users can invoke "
+ WebSecurity.
class
.getSimpleName
() +".addSecurityFilterChainBuilder directly"
); int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size(); List securityFilterChains =new
ArrayList<>( chainSize);for
(RequestMatcher ignoredRequest : ignoredRequests) { securityFilterChains.add(new
DefaultSecurityFilterChain(ignoredRequest)); }for
(SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) { securityFilterChains.add(securityFilterChainBuilder.build()); } FilterChainProxy filterChainProxy =new
FilterChainProxy(securityFilterChains);if
(httpFirewall !=null
) { filterChainProxy.setFirewall(httpFirewall); } filterChainProxy.afterPropertiesSet();/<code>
<code>Filter result = filterChainProxy;
if (debugEnabled) {
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);
}
postBuildAction.run();
return result;
/<code>
<code> } /<code>
首先計算出chainSize,也就是ignoredRequests.size() +
securityFilterChainBuilders.size();,如果你不配置ignoredRequests,那就是
securityFilterChainBuilders.size(),也就是HttpSecurity的個數,其本質上就是你一共配置幾個
WebSecurityConfigurerAdapter,因為每個
WebSecurityConfigurerAdapter對應一個HttpSecurity,而所謂的ignoredRequests就是FilterChainProxy的請求,默認是沒有的,如果你需要條跳過某些請求不需要認證或授權,可以如下配置:
<code>public
void
configure
(WebSecurity web)
throws
Exception { web.ignoring().antMatchers("/statics/**"
); } 在上面配置中,所有以/statics開頭請求都將被FilterChainProxy忽略。 /<code>
securityFilterChains.add(
securityFilterChainBuilder.build()); 這一行就是初始化所有的過濾器,記得上面有段代碼如下,將HttpSecurity設置到WebSecurity的
securityFilterChainBuilder中,上面就是調用HttpSecurity.build()方法,初始化所有的 HttpSecurity的過濾器鏈
<code>public
void
init
(
final
WebSecurity web)throws
Exception {final
HttpSecurity http = getHttp(); web.addSecurityFilterChainBuilder(http).postBuildAction(() -> { FilterSecurityInterceptor securityInterceptor = http .getSharedObject(FilterSecurityInterceptor.
class
); web.securityInterceptor(securityInterceptor); }); } /<code>
依然來到 doBuild()方法,只不過這次是執行的 HttpSecurity的
<code>protected
final
OdoBuild
()
throws
Exception {synchronized
(configurers) { buildState = BuildState.INITIALIZING;/<code>
<code>beforeInit
();init
();/<code>
<code>buildState
= BuildState.CONFIGURING;/<code>
<code>beforeConfigure
();configure
();/<code>
<code>buildState
= BuildState.BUILDING;/<code>
<code>O
result = performBuild();/<code>
<code>buildState
= BuildState.BUILT;/<code>
<code>return
result; } }/<code>
重點查看 configure()該方法 會調用對應的 過濾器配置的configure()如 再內部創建 SessionManagementFilter 最後添加到HttpSecurity中,也就是拿 HttpSecurity的configures 一個個創建出對應的過濾器
<code>public
void
configure
(H http)
{ SecurityContextRepository securityContextRepository = http .getSharedObject(SecurityContextRepository.
class
); SessionManagementFilter sessionManagementFilter =new
SessionManagementFilter( securityContextRepository, getSessionAuthenticationStrategy(http));if
(this
.sessionAuthenticationErrorUrl !=null
) { sessionManagementFilter.setAuthenticationFailureHandler(new
SimpleUrlAuthenticationFailureHandler(this
.sessionAuthenticationErrorUrl)); } InvalidSessionStrategy strategy = getInvalidSessionStrategy();if
(strategy !=null
) { sessionManagementFilter.setInvalidSessionStrategy(strategy); } AuthenticationFailureHandler failureHandler = getSessionAuthenticationFailureHandler();if
(failureHandler !=null
) { sessionManagementFilter.setAuthenticationFailureHandler(failureHandler); } AuthenticationTrustResolver trustResolver = http .getSharedObject(AuthenticationTrustResolver.
class
);if
(trustResolver !=null
) { sessionManagementFilter.setTrustResolver(trustResolver); } sessionManagementFilter = postProcess(sessionManagementFilter);/<code>
<code>http.addFilter(sessionManagementFilter);
if
(isConcurrentSessionControlEnabled()) {
ConcurrentSessionFilter
concurrentSessionFilter = createConcurrencyFilter(http);
/<code>
<code>concurrentSessionFilter
=postProcess(concurrentSessionFilter);
http.addFilter(concurrentSessionFilter);
}
}
/<code>
當doBuild()中的 configure();執行完畢後 的會得到如下HttpSecurity可以看到它內部的filters已經全部創建完畢
回到doBuild()方法 該方中有 performBuild() 調用HttpSecurity的 performBuild(),默認實現如下,先對上面所有的過濾器進行排序,使用的是 FilterComparator() 進行排序的,這裡不展開了,反正就是會排序成文章開始的那張圖上面的順序
<code>protected
DefaultSecurityFilterChainperformBuild
()
{ filters.sort(comparator);return
new
DefaultSecurityFilterChain(requestMatcher, filters); }/<code>
最後返回的是SecurityFilterChain的默認實現
DefaultSecurityFilterChain。
構建完所有SecurityFilterChain後,創建最為重要的FilterChainProxy實例,
<code> FilterChainProxy filterChainProxy =new
FilterChainProxy(securityFilterChains);/<code>
至此Spring Security 初始化完成,包括springSecurityFilterChain初始化,我們通過繼承
WebSecurityConfigurerAdapter來代達到個性化配置目的,文中提到了三個重要的個性化入口,並且
WebSecurityConfigurerAdapter是可以配置多個的,其對應的接口就是會存在多個SecurityFilterChain實例,但是它們人仍然在同一個FilterChainProxy中,通過RequestMatcher來匹配並傳入到對應的SecurityFilterChain中執行請求。
5.個性化入口配置(擴展WebSecurityConfigurerAdapter)
重要的個性化入口都是哪裡調用的 已經在上面初始化 springSecurityFilterChain 源碼中講解了,這裡知識總結一下
1、個性化配置入口之configure(
AuthenticationManagerBuilder auth)
我們可以通過繼承
WebSecurityConfigurerAdapter並重寫該方法來個性化配置
AuthenticationManagerBuilder。
2、個性化配置入口之configure(HttpSecurity http) 我們可以通過繼承
WebSecurityConfigurerAdapter並重寫該方法來個性化配置HttpSecurity。
3、個性化配置入口之configure(WebSecurity web) 我們可以通過繼承
WebSecurityConfigurerAdapter並重寫該方法來個性化配置WebSecurity。
實現
WebSecurityConfigurerAdapter經常需要重寫的:
<code>1
、configure
(AuthenticationManagerBuilder auth);/<code>
<code>2
、configure
(WebSecurity web);/<code>
<code>3
、configure
(HttpSecurity http); /<code>
6.總結
**本篇主要講解了 1.SpringBoot對於SpringSecurity的自動配置的支持類SecurityAutoConfiguration, 2.核心註解@EnableWebSecurity 3. SpringSecurity的核心過濾器鏈 springSecurityFilterChain 的初始化流程的源碼源碼部分還是定下心來多看 加油!**
個人博客網站
https://www.askajohnny.com 歡迎訪問!
本文由博客一文多發平臺 https://openwrite.cn?from=article_bottom 發佈!
關鍵字: 源碼 throws WebSecurity