中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring?Security認證的方法是什么

發布時間:2022-01-21 17:07:10 來源:億速云 閱讀:185 作者:iii 欄目:開發技術

今天小編給大家分享一下Spring Security認證的方法是什么的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

前言

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

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

認證上下文的持久化

處于最前面的過濾器叫做 SecurityContextPersistenceFilter,Spring Security 是通過 Session 來存儲認證信息的,這個過濾器的 doFilter 方法在每次請求中只執行一次,作用就是,在請求時,將 Session 中的 SecurityContext 放到當前請求的線程中(如果有),在響應時,檢查縣城中是否有 SecurityContext,有的話將其放入 Session。可以理解為將 SecurityContext 進行 Session 范圍的持久化。

認證信息的封裝

接著進入 UsernamePasswordAuthenticationFilter,這是基于用戶名/密碼認證過程中的主角之一。

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

這里最關鍵的代碼是 attemptAuthentication 方法(由 doFilter 方法調用),源碼如下:

@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 中獲取到的用戶名和密碼,構建了一個 UsernamePasswordAuthenticationToken 對象,我們可以看到這個構造方法的代碼,非常簡單:

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

只是保存了用戶名和密碼的引用,并且將認證狀態設置為 false,因為此時只是封裝了認證信息,還沒有進行認證。

我們再回到 attemptAuthentication 的代碼,在方法的最后一行,將創建好的認證信息,傳遞給了一個 AuthenticationManager 進行認證。這里實際工作的是 AuthenticationManager 的實現類 ProviderManager

查找處理認證的 Provider 類

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

ProviderManager 本身不執行認證操作,它管理著一個 AuthenticationProvider 列表,當需要對一個封裝好的認證信息進行認證操作的時候,它會將認證信息和它管理者的 Provider 們,逐一進行匹配,找到合適的 Provider 處理認證的具體工作。

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

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

那么,它是怎么將一個認證信息交給合適的 Provider 的呢?

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

認證邏輯

在 Spring Security 內置的 Provider 中,與 UsernamePasswordAuthenticationToken 對應的 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 ) ;
 }

代碼比較長,我們說要點:

  • 代碼第 12 行,通過 retrieveUser 方法,獲得 UserDetails 信息,這個方法的具體實現,可以在 DaoAuthenticationProvider 中找到,主要是通過 UserDetailsService 的 loadUserByUsername 方法,查找系統中的用戶信息。

  • 代碼第 25 行,通過 preAuthenticationChecks.check 方法,進行了認證前的一些校驗。校驗的具體實現可以在 DefaultPreAuthenticationChecks 內部類中找到,主要是判斷用戶是否鎖定、是否可用、是否過期。

  • 代碼第 26 行,通過 additionalAuthenticationChecks 方法,對用戶名和密碼進行了校驗。具體實現可以在 DaoAuthenticationProvider 中找到。

  • 代碼第 39 行,通過 postAuthenticationChecks.check 方法,校驗了密碼是否過期。具體實現可以在 DefaultPostAuthenticationChecks 內部類中找到。

  • 最后,如果以上校驗和認證都沒有問題,則通過 createSuccessAuthentication 方法,創建成功的認證信息,并返回。此時,就成功通過了認證。

在最后的 createSuccessAuthentication 方法中,會創建一個新的 UsernamePasswordAuthenticationToken 認證信息,這個新的認證信息的認證狀態為 true。表示這是一個已經通過的認證。

這個認證信息會返回到 UsernamePasswordAuthenticationFilter 中,并作為 attemptAuthentication 方法的結果。

doFilter 方法中,會根據認證成功或失敗的結果,調用相應的 Handler 類進行后續的處理,最后,認證的信息也會被保存在 SecurityContext 中,供后續使用。

以上就是“Spring Security認證的方法是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

哈巴河县| 黄梅县| 平泉县| 新宁县| 大渡口区| 从江县| 龙山县| 东平县| 江北区| 邵阳县| 阿拉善盟| 玉龙| 松滋市| 瓦房店市| 定结县| 望江县| 疏附县| 同德县| 滨海县| 苍溪县| 通榆县| 龙陵县| 和硕县| 玉田县| 利津县| 潢川县| 昭平县| 临湘市| 邳州市| 鲁山县| 日照市| 小金县| 旺苍县| 中方县| 乌兰察布市| 宁国市| 邢台市| 彝良县| 晋江市| 苏尼特左旗| 辽宁省|