Spring Security - AuthenticationManager

목차

참고

Spring Security - AuthenticationManager

AuthenticationManager 는 인증을 진행하는 AuthenticationProvider 객체들을 관리하는 객체다. AuthenticationManager 는 AuthenticationProvider 에 인증을 위임하는 형태로 인증을 진행한다.

public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}

ProviderManager

AuthenticationManager의 가장 대표적인 구현체

ProviderManager hierarchy

ProviderManager 에는 여러개의 AuthenticationProvider 객체들이 있다. 만약 현재의 ProviderManager에 인증을 처리할 AuthenticationProvider 객체가 없을 경우 Parent ProviderManager로 이동하게 된다. Parent ProviderManager 역시 AuthenticationProvider 객체들이 존재한다. 여기서의 Parent는 상속 개념이 아니라 field값으로 parent를 가지고 있다.

ProviderManager를 통한 인증 진행

ProviderManager 객체는 인증을 직접 진행하는 하지 않는다. 대신, 인증을 위한 다양한 AuthenticationProvider 객체들을 가지고 있고 AuthenticationProvider 객체에게 인증을 위임하는 형태로 인증을 진행한다.

  • ProviderManager에서 인증을 처리할 AuthenticationProvider 객체를 가져온다.
  • 가져온 AuthenticationProvider를 이용해 Authentication객체 인증을 진행
  • 인증이 완료 되면 새로운 Authentication 객체가 생성된다.
    • 현재 적절한 AuthenticationProvider 객체가 없다면 부모 ProviderManager로 이동해 인증을 시도한다.
    • 인증에 실패한 경우에는 ProviderNotFoundException 예외를 던진다.
  • Authentication 객체로 부터 Credentials 정보를 지우고 생성된 Authentication 객체를 반환한다.

ProviderManager.java

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Class<? extends Authentication> toTest = authentication.getClass();
Authentication result = null;
Authentication parentResult = null;

// 인증을 진행하기 위한 AuthenticationProvider를 가져온다.
for (AuthenticationProvider provider : getProviders()) {

// AuthenticationProvider가 Authentication 객체 인증을 지원하는지 확인
if (!provider.supports(toTest)) {
continue;
}

try {
// AuthenticationProvider 객체를 이용해 인증을 진행한다.
result = provider.authenticate(authentication);
if (result != null) {
// 기존의 Authentication 객체와 result를 이용해 새로운 Authentication 객체를 생성
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException | InternalAuthenticationServiceException ex) {
prepareException(ex, authentication);
throw ex;
}
catch (AuthenticationException ex) {
lastException = ex;
}
}

// 인증을 진행하기 위한 적절한 AuthenticationProvider 객체 없고 Parent AuthenticationProvider 객체가 존재하는 경우
// Parent AuthenticationProvider 로 이동해 인증을 진행한다.
if (result == null && this.parent != null) {
try {
parentResult = this.parent.authenticate(authentication);
result = parentResult;
}
catch (ProviderNotFoundException ex) {
}
catch (AuthenticationException ex) {
parentException = ex;
lastException = ex;
}
}

if (result != null) {
if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
// 인증을 완료한 후에 Authentication 객체에서 Credentials와 같은 민감한 정보를 지운다.
((CredentialsContainer) result).eraseCredentials();
}

if (parentResult == null) {
this.eventPublisher.publishAuthenticationSuccess(result);
}

// 인증이 완료된 Authentication 객체를 반환한다.
return result;
}

// 인증이 실패 했을 경우 ProviderNotFoundException 예외를 던진다.
if (lastException == null) {
lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound",
new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}"));
}

if (parentException == null) {
prepareException(lastException, authentication);
}
throw lastException;
}
Share