亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

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

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

Spring Security的登陸流程是什么

發布時間:2021-11-04 15:07:21 來源:億速云 閱讀:136 作者:iii 欄目:開發技術

本篇內容介紹了“Spring Security的登陸流程是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

在Spring Security中,認證授權都是通過過濾器來實現的。

當開始登陸的時候,有一個關鍵的過濾器UsernamePasswordAuthenticationFilter,該類繼承抽象類AbstractAuthenticationProcessingFilter,在AbstractAuthenticationProcessingFilter里有一個doFilter方法,一切先從這里說起。

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException {
   if (!requiresAuthentication(request, response)) {
      chain.doFilter(request, response);
      return;
   }
   try {
      Authentication authenticationResult = attemptAuthentication(request, response);
      if (authenticationResult == null) {
         // return immediately as subclass has indicated that it hasn't completed
         return;
      }
      this.sessionStrategy.onAuthentication(authenticationResult, request, response);
      // Authentication success
      if (this.continueChainBeforeSuccessfulAuthentication) {
         chain.doFilter(request, response);
      }
      successfulAuthentication(request, response, chain, authenticationResult);
   }
   catch (InternalAuthenticationServiceException failed) {
      this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
      unsuccessfulAuthentication(request, response, failed);
   }
   catch (AuthenticationException ex) {
      // Authentication failed
      unsuccessfulAuthentication(request, response, ex);
   }
}

首先requiresAuthentication先判斷是否嘗試校驗,通過后調用attemptAuthentication方法,這個方法也就是UsernamePasswordAuthenticationFilter 中的attemptAuthentication方法。

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);
}

1.在UsernamePasswordAuthenticationFilter 的attemptAuthentication方法中,先是驗證請求的類型,是否是POST請求,如果不是的話,拋出異常。(PS:登陸肯定要用POST方法了)
2.然后拿到username和password。這里使用的是obtainUsername方法,也就是get方法。

@Nullable
protected String obtainPassword(HttpServletRequest request) {
   return request.getParameter(this.passwordParameter);
}

@Nullable
protected String obtainUsername(HttpServletRequest request) {
   return request.getParameter(this.usernameParameter);
}

由此我們知道了Spring Security中是通過get方法來拿到參數,所以在進行前后端分離的時候是無法接受JSON數據,處理方法就是自定義一個Filter來繼承UsernamePasswordAuthenticationFilter,重寫attemptAuthentication方法,然后創建一個Filter實例寫好登陸成功和失敗的邏輯處理,在HttpSecurity參數的configure中通過addFilterAt來替換Spring Security官方提供的過濾器。
3.創建一個UsernamePasswordAuthenticationToken 實例。
4.設置Details,在這里關鍵的是在WebAuthenticationDetails類中記錄了用戶的remoteAddress和sessionId。

public WebAuthenticationDetails(HttpServletRequest request) {
   this.remoteAddress = request.getRemoteAddr();
   HttpSession session = request.getSession(false);
   this.sessionId = (session != null) ? session.getId() : null;
}

5.拿到一個AuthenticationManager通過authenticate方法進行校驗,這里以實現類ProviderManager為例。

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
   //獲取Authentication的運行時類
   Class<? extends Authentication> toTest = authentication.getClass();
   AuthenticationException lastException = null;
   AuthenticationException parentException = null;
   Authentication result = null;
   Authentication parentResult = null;
   int currentPosition = 0;
   int size = this.providers.size();
   
   for (AuthenticationProvider provider : getProviders()) {
       //判斷是否支持處理該類別的provider
      if (!provider.supports(toTest)) {
         continue;
      }
      if (logger.isTraceEnabled()) {
         logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",
               provider.getClass().getSimpleName(), ++currentPosition, size));
      }
      try {
          //獲取用戶的信息
         result = provider.authenticate(authentication);
         if (result != null) {
            copyDetails(authentication, result);
            break;
         }
      }
      catch (AccountStatusException | InternalAuthenticationServiceException ex) {
         prepareException(ex, authentication);
         // SEC-546: Avoid polling additional providers if auth failure is due to
         // invalid account status
         throw ex;
      }
      catch (AuthenticationException ex) {
         lastException = ex;
      }
   }
   //不支持的話跳出循環再次執行
   if (result == null && this.parent != null) {
      // Allow the parent to try.
      try {
         parentResult = this.parent.authenticate(authentication);
         result = parentResult;
      }
      catch (ProviderNotFoundException ex) {
         // 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 ex) {
         parentException = ex;
         lastException = ex;
      }
   }
   if (result != null) {
       //擦除用戶的憑證 也就是密碼
      if (this.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 then it
      // will publish an AuthenticationSuccessEvent
      // This check prevents a duplicate AuthenticationSuccessEvent if the parent
      // AuthenticationManager already published it
      if (parentResult == null) {
          //公示登陸成功
         this.eventPublisher.publishAuthenticationSuccess(result);
      }

      return result;
   }

   // Parent was null, or didn't authenticate (or throw an exception).
   if (lastException == null) {
      lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound",
            new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}"));
   }
   // If the parent AuthenticationManager was attempted and failed then 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;
}

 6.經過一系列校驗,此時登陸校驗基本完成,當驗證通過后會執行doFilter中的successfulAuthentication方法,跳轉到我們設置的登陸成功界面,驗證失敗會執行unsuccessfulAuthentication方法,跳轉到我們設置的登陸失敗界面。

“Spring Security的登陸流程是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

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

AI

新余市| 二连浩特市| 皮山县| 乌拉特中旗| 合山市| 广宁县| 安龙县| 安仁县| 呼玛县| 济阳县| 邢台市| 康定县| 辽阳市| 马尔康县| 抚远县| 凉山| 阿城市| 东安县| 石家庄市| 阿坝县| 枣强县| 马鞍山市| 陕西省| 林口县| 铜陵市| 上高县| 陆丰市| 渝中区| 东乡族自治县| 息烽县| 哈密市| 苗栗县| 西畴县| 汶川县| 无为县| 台中市| 西林县| 洪洞县| 托克逊县| 康马县| 郧西县|