스프링 시큐리티

Ch02. 스프링 시큐리티 주요 아키텍처 이해 - 인증 관리자(AuthenticationManager)

webmaster 2022. 1. 17. 10:27
728x90

동작과정

  • AuthenticationProvider 목록 중에서 인증 처리 요건에 맞는 AuthenticationProvider를 찾아 인증처리를 위임한다
    • 실제 인증은 하지 않는다(위임만 한다)
  • 부모 ProviderManager를 설정하여  AuthenticationProvider를 계속 탐색할 수 있다
  • ProviderManager가 인증에 맞는 Provider를 찾아 인증처리를 위임한다.
    • 만약 찾을 수 있는 Provider가 없을 경우 parent속성의 ProviderManager를 탐색하여, Provider를 찾는다.
    • Linked 형태로 부모와 자식 간의 관계를 형성할 수 있다
    • 자식에서 적절한 AuthenticationProvider를 찾지 못할 경우 계속 부모로 탐색하여 찾는 과정을 반복한다
    • AuthenticationManagerBuilder를 사용해서 스프링 시큐리티의 초기화 과정에서 설정한 기본 Parent 관계를 변경해야 권한 필터에서 재 인증 시 모든 AuthenticationProvider를 탐색할 수 있다
  • AuthenticationManagerBuilder.performBuild를 통해 ProviderManager를 생성한다..
  • @Override
    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;
       int currentPosition = 0;
       int size = this.providers.size();
       for (AuthenticationProvider provider : getProviders()) {
          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;
    }
    
    • ProviderManager
728x90