springSecurity之AuthenticationProvider用法解析
AuthenticationProvider解析
首先進入到AuthenticationProvider源碼中可以看到它只是個簡單的接口里面也只有兩個方法:
public interface AuthenticationProvider {
// 具體認證流程
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
// supports函數(shù)用來指明該Provider是否適用于該類型的認證,如果不合適,則尋找另一個Provider進行驗證處理。
boolean supports(Class<?> authentication);
}
AuthenticationProvider是用戶自定義身份認證,認證流程頂級接口。
唯一作用即使用來進行身份驗證,同時springSecurity也為我們提供了很多方便的實現(xiàn)類。

當我們沒有指定相關(guān)AuthenticationProvider 對象時springSecurity默認使用的就時上圖中的DaoAuthenticationProvider進行驗證。
也就是最常見的賬戶名密碼的方式。但是實際開發(fā)中我們往往需要實現(xiàn)自定義認證流程比如最常見的短信驗證碼,第三方登錄等等。
這個時候我們就可以通過實現(xiàn)自己的 AuthenticationProvider方式來進行自定義認證。
只需要在WebSecurityConfigurerAdapter適配器類的config方法中加入自己實現(xiàn)的AuthenticationProvider 即可。
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
說到AuthenticationProvider就離不開AuthenticationManager這個接口
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
同樣的AuthenticationManager也是一個頂級接口,可以看到它其中也定義了一個跟AuthenticationProvider一摸一樣的方法。
如果說Auth ntic ationProvider是對認證的具體實現(xiàn),則AuthenticationManager則是對我們眾多AuthenticationProvider的一個統(tǒng)一管理。
Authentication Ma nager的實現(xiàn)有很多,通常使用ProviderManager對認證請求鏈進行管理。

從源碼中可以看到
ProviderManager提供了一個list對AuthenticationProvider進行統(tǒng)一管理,即一個認證處理器鏈來支持同一個應用中的多個不同身份認證機制,ProviderManager將會根據(jù)順序來進行驗證。
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Class<? extends Authentication> toTest = authentication.getClass();
AuthenticationException lastException = null;
AuthenticationException parentException = null;
Authentication result = null;
Authentication parentResult = null;
boolean debug = logger.isDebugEnabled();
for (AuthenticationProvider provider : getProviders()) {
// 如果支持認證實現(xiàn)類就繼續(xù)處理
if (!provider.supports(toTest)) {
continue;
}
if (debug) {
logger.debug("Authentication attempt using "
+ provider.getClass().getName());
}
try {
// 調(diào)用實現(xiàn)類的authenticate方法進行真實業(yè)務邏輯認證處理
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException e) {
prepareException(e, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to
// invalid account status
throw e;
}
catch (InternalAuthenticationServiceException e) {
prepareException(e, authentication);
throw e;
}
catch (AuthenticationException e) {
lastException = e;
}
}
if (result == null && parent != null) {
// Allow the parent to try.
try {
result = parentResult = parent.authenticate(authentication);
}
catch (ProviderNotFoundException e) {
// ignore as we will throw below if no other exception occurred prior to
// calling parent and the parent
// may throw ProviderNotFound even though a provider in the child already
// handled the request
}
catch (AuthenticationException e) {
lastException = parentException = e;
}
}
if (result != null) {
if (eraseCredentialsAfterAuthentication
&& (result instanceof CredentialsContainer)) {
// Authentication is complete. Remove credentials and other secret data
// from authentication
((CredentialsContainer) result).eraseCredentials();
}
// If the parent AuthenticationManager was attempted and successful than it will publish an AuthenticationSuccessEvent
// This check prevents a duplicate AuthenticationSuccessEvent if the parent AuthenticationManager already published it
if (parentResult == null) {
// //發(fā)送認證成功事件
eventPublisher.publishAuthenticationSuccess(result);
}
return result;
}
// Parent was null, or didn't authenticate (or throw an exception).
if (lastException == null) {
lastException = new ProviderNotFoundException(messages.getMessage(
"ProviderManager.providerNotFound",
new Object[] { toTest.getName() },
"No AuthenticationProvider found for {0}"));
}
// If the parent AuthenticationManager was attempted and failed than it will publish an AbstractAuthenticationFailureEvent
// This check prevents a duplicate AbstractAuthenticationFailureEvent if the parent AuthenticationManager already published it
if (parentException == null) {
prepareException(lastException, authentication);
}
throw lastException;
}
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot整合freemarker和相應的語法詳解
FreeMarker是一款Spring官方推薦使用的模板引擎。接下來通過本文給大家介紹Springboot整合freemarker和相應的語法,感興趣的朋友一起看看吧2021-09-09

