最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Security認證器實現(xiàn)過程詳解

 更新時間:2022年06月24日 08:44:55   作者:阿弱  
一些權限框架一般都包含認證器和決策器,前者處理登陸驗證,后者處理訪問資源的控制,這篇文章主要介紹了Spring?Security認證器實現(xiàn)過程,需要的朋友可以參考下

一些權限框架一般都包含認證器和決策器,前者處理登陸驗證,后者處理訪問資源的控制

Spring Security的登陸請求處理如圖

下面來分析一下是怎么實現(xiàn)認證器的

攔截請求

首先登陸請求會被UsernamePasswordAuthenticationFilter攔截,這個過濾器看名字就知道是一個攔截用戶名密碼的攔截器

主要的驗證是在attemptAuthentication()方法里,他會去獲取在請求中的用戶名密碼,并且創(chuàng)建一個該用戶的上下文,然后在去執(zhí)行一個驗證過程

String username = this.obtainUsername(request);
String password = this.obtainPassword(request);
//創(chuàng)建上下文
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);

可以看看UsernamePasswordAuthenticationToken這個類,他是繼承了AbstractAuthenticationToken,然后這個父類實現(xiàn)了Authentication

由這個類的方法和屬性可得知他就是存儲用戶驗證信息的,認證器的主要功能應該就是驗證完成后填充這個類

回到UsernamePasswordAuthenticationToken中,在上面創(chuàng)建的過程了可以發(fā)現(xiàn)

public UsernamePasswordAuthenticationToken(Object principal,Object credentials){
    super(null);
    this.principal=principal;
    this.credentials=credentials;
    //還沒認證
    setAuthenticated(false);
}

還有一個super(null)的處理,因為剛進來是還不知道有什么權限的,設置null是初始化一個空的權限

//權限利集合
private final Collection<GrantedAuthority> authorities;
//空的集合
public static final List<GrantedAuthority> NO_AUTHORITIES = Collections.emptyList();
//初始化
if (authorities == null) {
    this.authorities = AuthorityUtils.NO_AUTHORITIES;
    return;
}

那么后續(xù)認證完還會把權限設置盡量,此時可以看UsernamePasswordAuthenticationToken的另一個重載構造器

//認證完成
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
    Collection<? extends GrantedAuthority> authorities) {
    super(authorities);
    this.principal = principal;
    this.credentials = credentials;
    super.setAuthenticated(true); // must use super, as we override
}

在看源碼的過程中,注釋一直在強調這些上下文的填充和設置都應該是由AuthenticationManager或者AuthenticationProvider的實現(xiàn)類去操作

驗證過程

接下來會把球踢給AuthenticationManager,但他只是個接口

/**
 * Attempts to authenticate the passed {@link Authentication} object, returning a
 * fully populated <code>Authentication</code> object (including granted authorities)
 * if successful.
 **/
public interface AuthenticationManager {
    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;
}

注釋也寫的很清楚了,認證完成后會填充Authentication

接下來會委托給ProviderManager,因為他實現(xiàn)了AuthenticationManager

剛進來看authenticate()方法會發(fā)現(xiàn)他先遍歷了一個List<AuthenticationProvider>集合

/**
 * Indicates a class can process a specific Authentication 
 **/
public interface AuthenticationProvider {
    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;
    //支不支持特定類型的authentication
    boolean supports(Class<?> authentication);
}

實現(xiàn)這個類就可以處理不同類型的Authentication,比如上邊的UsernamePasswordAuthenticationToken,對應的處理類是AbstractUserDetailsAuthenticationProvider,為啥知道呢,因為在這個supports()

public boolean supports(Class<?> authentication) {
		return (UsernamePasswordAuthenticationToken.class
				.isAssignableFrom(authentication));
}

注意到這個是抽象類,實際的處理方法是在他的子類DaoAuthenticationProvider里,但是最重要的authenticate()方法子類好像沒有繼承,看看父類是怎么實現(xiàn)這個方法的

首先是繼續(xù)判斷Authentication是不是特定的類

 Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
     () -> messages.getMessage(
     "AbstractUserDetailsAuthenticationProvider.onlySupports",
     "Only UsernamePasswordAuthenticationToken is supported"));

查詢根據用戶名用戶,這次就是到了子類的方法了,因為這個方法是抽象的

 user=retrieveUser(username,
     (UsernamePasswordAuthenticationToken)authentication);

接著DaoAuthenticationProvider會調用真正實現(xiàn)查詢用戶的類UserDetailsService

UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);

UserDetailsService這個類信息就不陌生了,我們一般都會去實現(xiàn)這個類來自定義查詢用戶的方式,查詢完后會返回一個UserDetails,當然也可以繼承這個類來擴展想要的字段,主要填充的是權限信息和密碼

檢驗用戶,如果獲取到的UserDetails是null,則拋異常,不為空則繼續(xù)校驗

//檢驗用戶合法性
preAuthenticationChecks.check(user);
//校驗密碼
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken) authentication);

第一個教育是判斷用戶的合法性,就是判斷UserDetails里的幾個字段

//賬號是否過期
boolean isAccountNonExpired();
//賬號被鎖定或解鎖狀態(tài)。
boolean isAccountNonLocked();
//密碼是否過期
boolean isCredentialsNonExpired();
//是否啟用
boolean isEnabled();

第二個則是由子類實現(xiàn)的,判斷從數(shù)據庫獲取的密碼和請求中的密碼是否一致,因為用的登陸方式是根據用戶名稱登陸,所以有檢驗密碼的步驟

 String presentedPassword = authentication.getCredentials().toString();
 if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
     logger.debug("Authentication failed: password does not match stored value");
     throw new BadCredentialsException(messages.getMessage(
     "AbstractUserDetailsAuthenticationProvider.badCredentials",
     "Bad credentials"));
 }

需要主要的是請求中的密碼是被加密過的,所以從數(shù)據庫獲取到的密碼也應該是被加密的

注意到當完成校驗的時候會把信息放入緩存

//當沒有從緩存中獲取到值時,這個字段會被設置成false
if (!cacheWasUsed) {
			this.userCache.putUserInCache(user);
 }
 //下次進來的時候回去獲取
 UserDetails user = this.userCache.getUserFromCache(username);

如果是從緩存中獲取,也是會走檢驗邏輯的

最后完成檢驗,并填充一個完整的Authentication

return createSuccessAuthentication(principalToReturn, authentication, user);

由上述流程來看,Security的檢驗過程還是比較清晰的,通過AuthenticationManager來委托給ProviderManager,在通過具體的實現(xiàn)類來處理請求,在這個過程中,將查詢用戶的實現(xiàn)和驗證代碼分離開來

整個過程看著像是策略模式,后邊將變化的部分抽離出來,實現(xiàn)解耦

返回完整的Authentication

前邊提到的認證成功會調用createSuccessAuthentication()方法,里邊的內容很簡單

UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
     principal, authentication.getCredentials(),
     authoritiesMapper.mapAuthorities(user.getAuthorities()));
     result.setDetails(authentication.getDetails());
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
        Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true); // must use super, as we override
        }

這次往supe里放了權限集合,父類的處理是判斷里邊的權限有沒有空的,沒有則轉換為只讀集合

for (GrantedAuthority a : authorities) {
    if (a == null) {
        throw new IllegalArgumentException(
        "Authorities collection cannot contain any null elements");
    }
}
ArrayList<GrantedAuthority> temp = new ArrayList<>(
authorities.size());
temp.addAll(authorities);
this.authorities = Collections.unmodifiableList(temp);

收尾工作

回到ProviderManager里的authenticate方法,當我們終于從

result = provider.authenticate(authentication);

走出來時,后邊還有什么操作

1.將返回的用戶信息負責給當前的上下文

  if (result != null) {
   	copyDetails(authentication, result);
   	break;
   }

2.刪除敏感信息

((CredentialsContainer) result).eraseCredentials();

這個過程會將一些字段設置為null,可以實現(xiàn)eraseCredentials()方法來自定義需要刪除的信息

最后返回到UsernamePasswordAuthenticationFilter中通過過濾

結論

這就是Spring Security實現(xiàn)認證的過程了

通過實現(xiàn)自己的上下文Authentication和處理類AuthenticationProvider以及具體的查詢用戶的方法就可以自定義自己的登陸實現(xiàn)
具體可以看Spring Security自定義認證器

    到此這篇關于Spring Security認證器實現(xiàn)過程詳解的文章就介紹到這了,更多相關Spring Security認證器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

    相關文章

    • Spring Boot 訪問安全之認證和鑒權詳解

      Spring Boot 訪問安全之認證和鑒權詳解

      這篇文章主要介紹了Spring Boot 訪問安全之認證和鑒權,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
      2021-11-11
    • java 基礎知識之網絡通信(TCP通信、UDP通信、多播以及NIO)總結

      java 基礎知識之網絡通信(TCP通信、UDP通信、多播以及NIO)總結

      這篇文章主要介紹了java 基礎知識之網絡通信總結的相關資料,包括TCP通信、UDP通信、多播以及NIO,需要的朋友可以參考下
      2017-03-03
    • java基礎--自己動手實現(xiàn)一個LRU

      java基礎--自己動手實現(xiàn)一個LRU

      這篇文章主要介紹了運用方案如何實現(xiàn)LUR,文章中通過代碼講解的非常詳細,對大家的工作或學習有一定的參考價值,感興趣的朋友可以參考一下
      2021-08-08
    • java.util.Date與java.sql.Date的區(qū)別

      java.util.Date與java.sql.Date的區(qū)別

      這篇文章主要介紹了java.util.Date與java.sql.Date的區(qū)別的相關資料,需要的朋友可以參考下
      2015-07-07
    • Spring Boot2.X國際化文件編寫配置

      Spring Boot2.X國際化文件編寫配置

      這篇文章主要介紹了Spring Boot2.X國際化文件編寫配置,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
      2020-02-02
    • jvm中指定時區(qū)信息user.timezone問題及解決方式

      jvm中指定時區(qū)信息user.timezone問題及解決方式

      同一份程序使用時間LocalDateTime類型,在國內和國外部署后,返回的時間信息前端使用出問題,這篇文章主要介紹了jvm中指定時區(qū)信息user.timezone問題及解決方法,需要的朋友可以參考下
      2023-02-02
    • 值得收藏的2017年Java開發(fā)崗位面試題

      值得收藏的2017年Java開發(fā)崗位面試題

      這篇文章主要為大家推薦一份值得收藏的2017年Java開發(fā)崗位面試題,具有一定的參考價值,感興趣的小伙伴們可以參考一下
      2017-08-08
    • 帶你深入理解MyBatis緩存機制

      帶你深入理解MyBatis緩存機制

      緩存是一般的ORM框架都會提供的功能,目的就是提升查詢的效率和減少數(shù)據庫的壓力,跟Hibernate 一樣,MyBatis 也有一級緩存和二級緩存,并且預留了集成第三方緩存的接口,這篇文章主要給大家介紹了關于MyBatis緩存機制的相關資料,需要的朋友可以參考下
      2021-10-10
    • Spring Boot實現(xiàn)功能的統(tǒng)一詳解

      Spring Boot實現(xiàn)功能的統(tǒng)一詳解

      這篇文章主要介紹了Spring Boot統(tǒng)一功能的處理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
      2022-06-06
    • Java Math.round函數(shù)詳解

      Java Math.round函數(shù)詳解

      這篇文章主要介紹了Java Math.round函數(shù)詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
      2021-08-08

    最新評論

    肥东县| 永兴县| 青铜峡市| 子长县| 醴陵市| 武城县| 孙吴县| 麻城市| 金塔县| 孙吴县| 新密市| 奎屯市| 枝江市| 丰都县| 新乡市| 岑巩县| 洛川县| 苏尼特左旗| 宾阳县| 达日县| 开平市| 尼玛县| 四平市| 抚州市| 岳阳县| 富源县| 庐江县| 安吉县| 乐都县| 渭南市| 鞍山市| 庐江县| 蓬安县| 德惠市| 阿瓦提县| 弋阳县| 蓬溪县| 南召县| 大荔县| 德化县| 龙江县|