Spring?Security中如何獲取AuthenticationManager對象
有時需要使用AuthenticationManager(以下簡稱Manager)對象,可是這個對象不是Bean,沒有直接保存在Spring的Bean庫中。那么如何獲取Spring Security中的這個對象呢?
在Spring Security 5.7.0-M2之前,通常會擴展WebSecurityConfigurerAdapter(以下簡稱Adapter)類來自定義網(wǎng)絡(luò)安全配置。Adapter類中有一個方法authenticationManager()可以提供Manager對象。但是從Spring Security 5.7.0-M2開始,Adapter類就被棄用,再用此類中的authenticationManager()方法獲取Manager對象就不合適了。
以下是Adapter#authenticationManager()方法的源碼。
protected AuthenticationManager authenticationManager() throws Exception { if (!this.authenticationManagerInitialized) { configure(this.localConfigureAuthenticationBldr); if (this.disableLocalConfigureAuthenticationBldr) { this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager(); } else { this.authenticationManager = this.localConfigureAuthenticationBldr.build(); } this.authenticationManagerInitialized = true; } return this.authenticationManager; }
可以發(fā)現(xiàn)在該方法中使用Adapter類的私有字段authenticationConfiguration的getAuthenticationManager()方法獲取Manager對象。而字段authenticationConfiguration是使用方法setAthenticationConfiguration()自動注入的,所以Spring的Bean庫中存在Manager對象。由此可得到如下獲取AuthenticationManager對象的方案一。
方案一:從Spring的Bean庫中獲取AuthenticationConfiguration(以下簡稱Configuration)對象,然后使用Configuration對象的getAuthenticationManager()方法獲取Manager對象。(關(guān)于如何從Spring中獲取Bean,本文不作介紹,請讀者自行查閱資料了解)
繼續(xù)查看Configuration#getAuthenticationManager()方法的源碼。
public AuthenticationManager getAuthenticationManager() throws Exception { if (this.authenticationManagerInitialized) { return this.authenticationManager; } AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class); if (this.buildingAuthenticationManager.getAndSet(true)) { return new AuthenticationManagerDelegator(authBuilder); } for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) { authBuilder.apply(config); } this.authenticationManager = authBuilder.build(); if (this.authenticationManager == null) { this.authenticationManager = getAuthenticationManagerBean(); } this.authenticationManagerInitialized = true; return this.authenticationManager; }
源碼中展示的流程如下。
① 如果Configuration對象中已保存有Manager對象,則返回該對象。
② 如果Configuration對象中沒有Manager對象,則從Spring的Bean庫中獲取AuthenticationManagerBuilder(以下簡稱Builder)對象。
③ 如果已經(jīng)用Builder對象構(gòu)建了Manager對象,則返回一個使用Builder對象初始化的AuthenticationManagerDelegator對象。
④ AuthenticationManagerDelegator是Manager的子類。該類代理了另一個Manager對象,被代理的Manager對象是使用Builder對象的getObject()方法獲得的。Builder#getObject()的代碼表明,在調(diào)用該方法前,需要先在Builder對象內(nèi)構(gòu)建一個Manager。也就是說可以從Spring的Bean庫中獲取Builder對象,然后用它的getObject()方法獲得Manager對象。
@Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { if (this.delegate != null) { return this.delegate.authenticate(authentication); } synchronized (this.delegateMonitor) { if (this.delegate == null) { this.delegate = this.delegateBuilder.getObject(); this.delegateBuilder = null; } } return this.delegate.authenticate(authentication); }
⑤ 如果尚未使用Builder對象構(gòu)建Manager對象,則先把Configuration的私有字段globalAuthConfigurers的數(shù)據(jù)應(yīng)用在Builder對象上(私有字段globalAuthConfigurers是通過方法setGlobalAuthConfigurers()自動注入的)。
⑥ 然后使用Builder對象的build()方法構(gòu)建Manager對象。
⑦ 在Builder#build()方法中,第一次調(diào)用該方法會使用doBuild()方法生成Manager對象(不分析doBuild()方法),并將這個對象緩存下來。以后再調(diào)用build()方法將會拋出AlreadyBuiltException異常。也就是說可以從Spring的Bean庫中獲取Builder對象,然后用它的build()方法獲得Manager對象。
@Override public final O build() throws Exception { if (this.building.compareAndSet(false, true)) { this.object = doBuild(); return this.object; } throw new AlreadyBuiltException("This object has already been built"); }
⑧ 如果Builder對象未能成功構(gòu)建Manager對象,則使用Configuration的私有方法lazyBean()方法獲取Manager對象(不分析lazyBean()方法)。
上述流程表明,可以從Spring的Bean庫中獲取AuthenticationManagerBuilder對象,然后使用該對象的build()方法或getObject()方法獲取AuthenticationManager對象。獲取AuthenticationManager對象的方案二如下。
方案二:從Spring的Bean庫中獲取AuthenticationManagerBuilder對象,首先調(diào)用該對象的build()方法獲取Manager對象,并對方法調(diào)用捕獲AlreadyBuiltException異常。若捕獲到異常,則在異常處理代碼中調(diào)用Builder對象的getObject()方法獲取Manager對象。
方案二可能有缺陷。在Configuration#getAuthenticationManager()方法的源碼中可以看到步驟⑤對Builder對象對象做了處理,而方案二并沒有做這種處理,推薦使用方案一。
到此這篇關(guān)于在Spring Security中如何獲取AuthenticationManager對象的文章就介紹到這了,更多相關(guān)Spring Security 獲取AuthenticationManager對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java公眾平臺通用接口工具類HttpConnectUtil實例代碼
下面小編就為大家分享一篇java公眾平臺通用接口工具類HttpConnectUtil實例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01Java集合List和Map互轉(zhuǎn)的方法總結(jié)
有時候我們需要將給定的List轉(zhuǎn)換為Map,或者Map轉(zhuǎn)換為List,本文主要介紹了Java集合List和Map互轉(zhuǎn)的方法總結(jié),具有一定的參考價值,感興趣的可以了解一下2023-09-09阿里的Easyexcel讀取Excel文件的方法(最新版本)
這篇文章主要介紹了阿里的Easyexcel讀取Excel文件(最新版本)的方法,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-12-12詳解Java?ThreadPoolExecutor的拒絕策略
這篇文章主要介紹了Java?ThreadPoolExecutor的拒絕策略,本文對于線程的池的幾種策略進行詳細的講解,在實際的生產(chǎn)中需要集合相關(guān)的場景來選擇合適的拒絕策略,需要的朋友可以參考下2022-08-08