亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring?Security認(rèn)證的完整流程記錄

 更新時(shí)間:2022年01月21日 12:44:55   作者:Pseudocode  
相信大伙對Spring Security這個(gè)框架又愛又恨,愛它的強(qiáng)大,恨它的繁瑣,下面這篇文章主要給大家介紹了關(guān)于Spring?Security認(rèn)證流程的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

本文以用戶名/密碼驗(yàn)證方式為例,講解 Spring Security 的認(rèn)證流程,在此之前,需要你了解 Spring Security 用戶名/密碼認(rèn)證的基本配置。

Spring Security 是基于過濾器的,通過一層一層的過濾器,處理認(rèn)證的流程,攔截非法請求。

認(rèn)證上下文的持久化

處于最前面的過濾器叫做 SecurityContextPersistenceFilter,Spring Security 是通過 Session 來存儲(chǔ)認(rèn)證信息的,這個(gè)過濾器的 doFilter 方法在每次請求中只執(zhí)行一次,作用就是,在請求時(shí),將 Session 中的 SecurityContext 放到當(dāng)前請求的線程中(如果有),在響應(yīng)時(shí),檢查縣城中是否有 SecurityContext,有的話將其放入 Session??梢岳斫鉃閷?SecurityContext 進(jìn)行 Session 范圍的持久化。

認(rèn)證信息的封裝

接著進(jìn)入 UsernamePasswordAuthenticationFilter,這是基于用戶名/密碼認(rèn)證過程中的主角之一。

默認(rèn)情況下,這個(gè)過濾器會(huì)匹配路徑為 /login 的 POST 請求,也就是 Spring Security 默認(rèn)的用戶名和密碼登錄的請求路徑。

這里最關(guān)鍵的代碼是 attemptAuthentication 方法(由 doFilter 方法調(diào)用),源碼如下:

@Override
public Authentication attemptAuthentication ( HttpServletRequest request, HttpServletResponse response )
 throws AuthenticationException {
 if ( this.postOnly && !request.getMethod () .equals ( "POST" )) {
 throw new AuthenticationServiceException ( "Authentication method not supported: " + request.getMethod ()) ;
   }
 String username = obtainUsername ( request ) ;
   username = ( username != null ) ? username : "";
   username = username.trim () ;
   String password = obtainPassword ( request ) ;
   password = ( password != null ) ? password : "";
   UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken ( username, password ) ;
   // Allow subclasses to set the "details" property
   setDetails ( request, authRequest ) ;
   return this.getAuthenticationManager () .authenticate ( authRequest ) ;
 }

attemptAuthentication 方法代碼的第 12 行,使用從 request 中獲取到的用戶名和密碼,構(gòu)建了一個(gè) UsernamePasswordAuthenticationToken 對象,我們可以看到這個(gè)構(gòu)造方法的代碼,非常簡單:

public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
    super((Collection)null);
    this.principal = principal;
    this.credentials = credentials;
    this.setAuthenticated(false);
}

只是保存了用戶名和密碼的引用,并且將認(rèn)證狀態(tài)設(shè)置為 false,因?yàn)榇藭r(shí)只是封裝了認(rèn)證信息,還沒有進(jìn)行認(rèn)證。

我們再回到 attemptAuthentication 的代碼,在方法的最后一行,將創(chuàng)建好的認(rèn)證信息,傳遞給了一個(gè) AuthenticationManager 進(jìn)行認(rèn)證。這里實(shí)際工作的是 AuthenticationManager 的實(shí)現(xiàn)類 ProviderManager。

查找處理認(rèn)證的 Provider 類

進(jìn)入 ProviderManager 可以從源碼中找到 authenticate 方法,代碼比較長,我就不貼在這里了,你可以自行查找,我簡述一下代碼中的邏輯。

ProviderManager 本身不執(zhí)行認(rèn)證操作,它管理著一個(gè) AuthenticationProvider 列表,當(dāng)需要對一個(gè)封裝好的認(rèn)證信息進(jìn)行認(rèn)證操作的時(shí)候,它會(huì)將認(rèn)證信息和它管理者的 Provider 們,逐一進(jìn)行匹配,找到合適的 Provider 處理認(rèn)證的具體工作。

可以這樣理解,ProviderManager 是一個(gè)管理者,管理著各種各樣的 Provider。當(dāng)有工作要做的時(shí)候,它從來都不親自去做,而是把不同的工作,分配給不同的 Provider 去操作。

最后,它會(huì)將 Provider 的工作成果(已認(rèn)證成功的信息)返回,或者拋出異常。

那么,它是怎么將一個(gè)認(rèn)證信息交給合適的 Provider 的呢?

在上一部分中,我們說到,認(rèn)證信息被封裝成了一個(gè) UsernamePasswordAuthenticationToken,它是Authentication 的子類,ProviderManager 會(huì)將這個(gè)認(rèn)證信息的類型,傳遞個(gè)每個(gè) Provider 的 supports 方法,由 Provider 來告訴 ProviderManager 它是不是支持這個(gè)類型的認(rèn)證信息。

認(rèn)證邏輯

在 Spring Security 內(nèi)置的 Provider 中,與 UsernamePasswordAuthenticationToken 對應(yīng)的 Provider 是 DaoAuthenticationProviderauthenticate 方法在它的父類 AbstractUserDetailsAuthenticationProvider 中。我們來看它的 authenticate 方法:

@Override
public Authentication authenticate ( Authentication authentication ) throws AuthenticationException {
 Assert.isInstanceOf( UsernamePasswordAuthenticationToken.class, authentication,
         () -> this.messages.getMessage ( "AbstractUserDetailsAuthenticationProvider.onlySupports",
               "Only UsernamePasswordAuthenticationToken is supported" )) ;
   String username = determineUsername ( authentication ) ;
   boolean cacheWasUsed = true;
   UserDetails user = this.userCache.getUserFromCache ( username ) ;
   if ( user == null ) {
 cacheWasUsed = false;
      try {
 user = retrieveUser ( username, ( UsernamePasswordAuthenticationToken ) authentication ) ;
      }
 catch ( UsernameNotFoundException ex ) {
 this.logger.debug ( "Failed to find user '" + username + "'" ) ;
         if ( !this.hideUserNotFoundExceptions ) {
 throw ex;
         }
 throw new BadCredentialsException ( this.messages
               .getMessage ( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials" )) ;
      }
 Assert.notNull( user, "retrieveUser returned null - a violation of the interface contract" ) ;
   }
 try {
 this.preAuthenticationChecks.check ( user ) ;
      additionalAuthenticationChecks ( user, ( UsernamePasswordAuthenticationToken ) authentication ) ;
   }
 catch ( AuthenticationException ex ) {
 if ( !cacheWasUsed ) {
 throw ex;
      }
 // There was a problem, so try again after checking
      // we're using latest data (i.e. not from the cache)
      cacheWasUsed = false;
      user = retrieveUser ( username, ( UsernamePasswordAuthenticationToken ) authentication ) ;
      this.preAuthenticationChecks.check ( user ) ;
      additionalAuthenticationChecks ( user, ( UsernamePasswordAuthenticationToken ) authentication ) ;
   }
 this.postAuthenticationChecks.check ( user ) ;
   if ( !cacheWasUsed ) {
 this.userCache.putUserInCache ( user ) ;
   }
 Object principalToReturn = user;
   if ( this.forcePrincipalAsString ) {
 principalToReturn = user.getUsername () ;
   }
 return createSuccessAuthentication ( principalToReturn, authentication, user ) ;
 }

代碼比較長,我們說要點(diǎn):

  • 代碼第 12 行,通過 retrieveUser 方法,獲得 UserDetails 信息,這個(gè)方法的具體實(shí)現(xiàn),可以在 DaoAuthenticationProvider 中找到,主要是通過 UserDetailsService 的 loadUserByUsername 方法,查找系統(tǒng)中的用戶信息。
  • 代碼第 25 行,通過 preAuthenticationChecks.check 方法,進(jìn)行了認(rèn)證前的一些校驗(yàn)。校驗(yàn)的具體實(shí)現(xiàn)可以在 DefaultPreAuthenticationChecks 內(nèi)部類中找到,主要是判斷用戶是否鎖定、是否可用、是否過期。
  • 代碼第 26 行,通過 additionalAuthenticationChecks 方法,對用戶名和密碼進(jìn)行了校驗(yàn)。具體實(shí)現(xiàn)可以在 DaoAuthenticationProvider 中找到。
  • 代碼第 39 行,通過 postAuthenticationChecks.check 方法,校驗(yàn)了密碼是否過期。具體實(shí)現(xiàn)可以在 DefaultPostAuthenticationChecks 內(nèi)部類中找到。
  • 最后,如果以上校驗(yàn)和認(rèn)證都沒有問題,則通過 createSuccessAuthentication 方法,創(chuàng)建成功的認(rèn)證信息,并返回。此時(shí),就成功通過了認(rèn)證。

在最后的 createSuccessAuthentication 方法中,會(huì)創(chuàng)建一個(gè)新的 UsernamePasswordAuthenticationToken 認(rèn)證信息,這個(gè)新的認(rèn)證信息的認(rèn)證狀態(tài)為 true。表示這是一個(gè)已經(jīng)通過的認(rèn)證。

這個(gè)認(rèn)證信息會(huì)返回到 UsernamePasswordAuthenticationFilter 中,并作為 attemptAuthentication 方法的結(jié)果。

doFilter 方法中,會(huì)根據(jù)認(rèn)證成功或失敗的結(jié)果,調(diào)用相應(yīng)的 Handler 類進(jìn)行后續(xù)的處理,最后,認(rèn)證的信息也會(huì)被保存在 SecurityContext 中,供后續(xù)使用。

總結(jié)

到此這篇關(guān)于Spring Security認(rèn)證流程的文章就介紹到這了,更多相關(guān)Spring Security認(rèn)證流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java順時(shí)針打印矩陣

    Java順時(shí)針打印矩陣

    這篇文章主要為大家詳細(xì)介紹了Java順時(shí)針打印矩陣,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • Java中GC的工作原理詳細(xì)介紹

    Java中GC的工作原理詳細(xì)介紹

    這篇文章主要介紹了Java中GC的工作原理詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Spring框架中@PostConstruct注解詳解

    Spring框架中@PostConstruct注解詳解

    在Spring項(xiàng)目經(jīng)常遇到@PostConstruct注解,下面這篇文章主要給大家介紹了關(guān)于Spring框架中@PostConstruct注解的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • Spring基于注解配置AOP詳解

    Spring基于注解配置AOP詳解

    這篇文章主要介紹了Spring基于注解配置AOP詳解,Spring 的 AOP 功能是基于 AspectJ 實(shí)現(xiàn)的,支持使用注解聲明式定義 AOP 切面,Spring 基于注解配置 AOP 需要啟用 AspectJ 自動(dòng)代理功能,需要的朋友可以參考下
    2023-09-09
  • java調(diào)用dll方法總結(jié)

    java調(diào)用dll方法總結(jié)

    本篇文章小編給大家整理了java調(diào)用dll的方法的總結(jié),有需要的朋友參考學(xué)下一下吧。
    2017-12-12
  • Java實(shí)現(xiàn)獲取某年某月第一天/最后一天的方法

    Java實(shí)現(xiàn)獲取某年某月第一天/最后一天的方法

    這篇文章主要介紹了Java實(shí)現(xiàn)獲取某年某月第一天/最后一天的方法,涉及java日期運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下
    2018-02-02
  • ThreadLocal導(dǎo)致JVM內(nèi)存泄漏原因探究

    ThreadLocal導(dǎo)致JVM內(nèi)存泄漏原因探究

    ThreadLocal是JDK提供的線程本地變量機(jī)制,但若使用不當(dāng)可能導(dǎo)致內(nèi)存泄漏。正確的使用方式是在使用完后及時(shí)remove,或者使用弱引用等手段避免強(qiáng)引用導(dǎo)致的內(nèi)存泄漏。在多線程編程中,合理使用ThreadLocal可以提高并發(fā)性能,但也需要注意其潛在的內(nèi)存泄漏問題
    2023-04-04
  • jar包中替換指定的class文件方法詳解

    jar包中替換指定的class文件方法詳解

    這篇文章主要為大家介紹了jar包中替換指定的class文件方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Spring Boot Admin 環(huán)境搭建與基本使用詳解

    Spring Boot Admin 環(huán)境搭建與基本使用詳解

    這篇文章主要介紹了Spring Boot Admin 環(huán)境搭建與基本使用,本文主要是對于Spring Boot Admin的基本認(rèn)識(shí)和基本運(yùn)用,通過本篇博客能夠?qū)pring Boot Admin有一個(gè)宏觀認(rèn)知和能夠快速上手,需要的朋友可以參考下
    2023-08-08
  • 使用IDEA如何導(dǎo)入SpringBoot項(xiàng)目

    使用IDEA如何導(dǎo)入SpringBoot項(xiàng)目

    這篇文章主要介紹了使用IDEA如何導(dǎo)入SpringBoot項(xiàng)目問題,具有很好的參考價(jià)值,希望對大家有所幫助,
    2023-12-12

最新評(píng)論