BackEnd/Spring Security

[Spring Security] AuthenticationProvider

샤아이인 2022. 9. 2.

본 글은 Spring Security docs 와 여러 블로그 들을 참고하고, 공부하면서 요약하였습니다.

 

https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-authenticationprovider

 

Servlet Authentication Architecture :: Spring Security

ProviderManager is the most commonly used implementation of AuthenticationManager. ProviderManager delegates to a List of AuthenticationProviders. Each AuthenticationProvider has an opportunity to indicate that authentication should be successful, fail, or

docs.spring.io

 

1. AuthenticationProvider

이번시간에는 AuthenticationProvier에 대하여 학습해보자.

 

AuthenticationProvider 는 인터페이스다. 두 개의 메서드가 제공된다.

public interface AuthenticationProvider {

    Authentication authenticate(Authentication authentication) throws AuthenticationException;
    
    boolean supports(Class<?> authentication);
}

 

authenticate(authentication) : 실제적인 인증처리를 위한 검증 메서드
supports(authentication): 인증처리가 가능한 Provider인지 검사하는 메서드


두 개의 메서드는 사용자가 입력한 아이디와 패스워드가 들어간 authentication객체를 가지고 로직을 수행한다.

 

  1. 아이디 검증
    • UserDetailsService 인터페이스를 구현한 구현체에서 인증해야하는 사용자의 정보를 조회한다. 
      • 존재할 경우 UserDetails 타입으로 반환한다.
      • 존재하지 않을 경우 UserNotFoundException 발생.
  2. 패스워드 검증
    • 반환된 UserDetails에 저장된 password와 로그인시 입력한 패스워드(authentication.password)가 일치하는지 비교한다.
      • 일치하지 않을 경우 BadCredentialException 발생
    • 일반적으로 패스워드를 저장할 때 Password Encoder를 이용해 암호화 하여 저장하기 때문에 해당 클래스(PasswordEncoder)를 이용해 두 암호를 비교한다.
  3. 추가 검증
    • 추가적으로 사용자가 정의한 검증 조건 검증
    • autheticate(authentication)  에서 검증이 모두 성공하면 최종적으로 인증객체(Authentication)를 생성하여 AuthenticationManager에 전달한다.

 

2. 디버깅 해보기

로그인을 시도하면 AuthenticationProvier의 구현체인 AbstractUserDetailsAuthenticationProvider(추상 클래스) 가 호출된다.

authenticate() 메서드 내부를 보면 우선 retrieveUser롤 통해 해당 유저를 찾아오게 된다.

retrieveUser() 는 추상메서드 이기 때문에 하부 구현체에서 이를 구현하게 된다.

우리는 Form 로그인을 시도했으니, DaoAuthenticationProvider에서 이를 구현하게 된다. 다음 코드를 살펴보자.

 

다음으로 loadUserByUsername을 통해 인자로 username을 전달하여 UserDetails를 찾아오자

여기서는 처음에 메모리에 저장된 회원을 불러오기떄문에 this가 InMemory에 해당된다.

이렇게 찾아온 UserDetails를 반환시킨다.

 

반횐된 UserDetails는 다시 DaoAuthenticationProvider로 전달된다.

이렇게 전달된 UserDetails는 DaoAuthenticationProvider의 additionalAuthenticationChecks()를 호출할때 인자로 전달시키게 된다.

여기서 password 매칭을 한다.

만약 password 인증에 실패한다면 BadCredentialsException이 발생하고, password 인증에 성공했다면 이를 Token으로 만들어서 반환시키게 된다. 다음 코드처럼 말이다.

AbstractUserDetailsAuthenticationProvider#createSuccessAuthentication()을 통해서 UsernamePasswordAuthenticationToken 생성하여 ProviderManager로 반환한다.

 

ProviderManager로 반환된 token은 다시 UsernamePasswordAuthenticationFilter 까지 전달되고 여기서 successfulAuthentication을 거쳐 ContextHolder에 저장된다.

 

3. 출처

https://catsbi.oopy.io/f9b0d83c-4775-47da-9c81-2261851fe0d0

 

스프링 시큐리티 주요 아키텍처 이해

목차

catsbi.oopy.io

 

댓글