[Spring Security] ProviderManager와 AuthenticationProvider 사용하기

본 포스팅은 ProviderManager와 AuthenticationProvider가 무엇인지 이해하고 이들을 이용해 인증하는 방법을 공부합니다.

 

 

ProviderManager


ProviderManager는 이름에서도 알 수 있듯이 provider를 관리하는 manager클래스 입니다.

예를 들어, 어떤 일을 하는데 작업을 하는 사람만 있다면 작업자들은 어떤 일을 누가 해야 할지 모를 수 있는데, 작업을 관리하는 관리자가 있다면 어떤 작업을 어떤 사람이 할지 지시를 해줌으로써 좀 더 효율적으로 작업을 할 수 있습니다.

 

이처럼 인증 작업을 어떤 클래스가 할지 정해주는 역할을 하는 것이 ProviderManager입니다.

즉, 인증 작업을 관리하는 매니저라고 생각할 수 있습니다.

 

ProviderManager는 AuthenticationManager의 구현체로 여러 개의 AuthenticaionProvider를 관리하는 역할을 합니다.

 

ProviderManager 클래스를 살펴보도록 하겠습니다.

 

 

여러 개의 provider를 관리하기 위해 AuthenticaionProvider를 리스트 형태로 필드에서 관리하고 있습니다. 

 

ProviderManager를 생성할 때, AuthenticaionProvider 리스트를 파라미터로 전달해 ProviderManager가 실제로 인증작업을 하는  provider들을 갖도록 하고 있습니다.

 

ProviderManager의 authenticate() 메서드를 호출하면 ProviderManager는 자신이 갖고 있는 AuthenticaionProvider 중 어떤 provider에게 인증 작업을 맡길지 결정을 합니다.

 

authenticate() 메서드의 일부분을 살펴보도록 하겠습니다.

 

 

인증 작업의 핵심이 되는 부분만 간단히 보도록 하겠습니다.

  1. authenticate() 메서드는 인증할 객체를 파라미터로 전달받아 해당 인증 객체의 클래스를 가져옵니다.
  2. 자신이 갖고 있는 provider를 하나씩 가져와서 provider의 supprot() 메서드를 호출해 해당 인증 객체를 자신이 처리할 인증 객체인지 확인을 합니다. 이 support() 메서드는 AuthenticationProvider 설명할 때 다시 알아보도록 하겠습니다. 지금은 자신(provider)이 인증 작업을 진행할지 말지 결정하는 메서드라고 생각하겠습니다.
  3. 인증할 수 있는 AuthenticationProvider가 발견되면 해당 provicder의 authenticate 메서드를 호출해 실제로 인증 작업을 합니다
  4. 인증에 성공하면 결과를 반환하고, 실패하면 다음 AuthenticationProvider로 이동해 다시 인증 절차를 시작합니다.
  5. 만일 모든 AuthenticationProvider가 실패하면 AuthenticationException 예외가 발생합니다.

 

 

AuthenticationProvider


AuthenticationProvider는 실제로 인증을 진행하는 메서드를 정의하고 있는 인터페이스입니다.

 

 

AuthenticationProvider는 authenticate() 메서드와, support() 메서드를 정의하고 있는데 예시 코드를 보면서 역할을 하나씩 알아보도록 하겠습니다.

 

public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) 
            throws AuthenticationException {
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();
        
        // 여기서 실제 인증 로직을 구현합니다.
        
        if (인증 성공 조건) {
            return new UsernamePasswordAuthenticationToken(username, password, List.of(사용자 권한));
        } 
        
        throw new BadCredentialsException("Invalid username or password");
    }

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

 

우선 AuthenticationProvider를 구현하는 CustomAuthenticationProvider를 만들어 authenticate(), support() 메서드를 오버라이드 합니다.

 

authenticate()

authenticate() 메서드는 인증할 객체를 파라미터로 전달받아 해당 인증 객체를 이용해 인증 작업을 시작합니다.

자신의 상황에 맞게 인증 로직을 구현하고 인증에 성공하면 인증이 된 Authentication 객체를 리턴하고 실패하면 AuthenticationException예외를 던지도록 합니다.

 

 

support()

support() 메서드는 위에서 잠시 언급했듯이 전달받은 Authentication객체를 인증할지 말지 결정하는 메서드입니다.

위 예시코드에서는, CustomAuthenticationProvider 클래스는 UsernamePasswordAuthenticationToken 클래스만 인증하도록 구현했습니다.

 

isAssignableFrom() 메서드를 이용해 파라미터로 전달받은 Authentication 클래스가 UsernamePasswordAuthenticationToken클래스의 하위 클래스 또는 UsernamePasswordAuthenticationToken클래스인지 확인합니다.

 

 

정리


ProviderManager와 AuthenticationProvider를 이용해 인증을 하는 전체적인 흐름은 실제로 인증을 처리할 커스텀한 provider클래스들을 만들어 이 AuthenticationProvider인터페이스를 구현하여 ProviderManager에 등록하고 ProviderManager의 authenticate() 메서드를 호출하면 적절한 provider에게 인증을 처리하도록 위임을 하게 됩니다.

 

 

ProviderManager와 AuthenticationProvider의 관계와 어떻게 동작하는지 간단하게 살펴보았습니다.