참고 : https://velog.io/@on5949/SpringSecurity-Authentication-과정-정리
위 링크가 너무나도 도움이 되었습니다. 제가 부족하다면 참고하시면 좋을것 같습니다.
아래 Authentication 객체에서 authenticate 라는 메서드에서 실제 비밀번호 인증을 진행합니다.
이때 AuthenticationManger - provider - userdetailsService 순서대로 인증을 진행한다고 합니다.
그러나 저는 userDetailsService 를 override하여 유저 정보를 가져오는 것만 구현했는데 어떻게 인증이 진행되는 것인지 궁금했습니다.
이에 의문점이 생겨서 코드를 뜯어보게 되었습니다.
@Transactional
public TokenDto signIn(SignInDto signInDto) {
//아이디 패스워드로 Authentication 객체 생성
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(
signInDto.getUserId(), signInDto.getPassword()
);
//실제 검증
//AuthenticationManger - provider - userdetail service 로 인증
Authentication authentication = authenticationManagerBuilder
.getObject()
.authenticate(authenticationToken);
TokenDto tokenDto = jwtTokenProvider.generateToken(authentication);
return tokenDto;
}
위 코드에서 UsernamePasswordAuthenticationToken 은 AbstractAuthenticationToken 을 상속(extends) 받아 사용하고, 이는 Authentication를 구현하고 있습니다.
따라서 Authentication 에 해당하는 변수에 사용할 수 있습니다.

UsernamePasswordAuthenticationToken 는 아이디 비밀번호만 가지고 있고 Authenticated 가 false로 설정되어 있습니다.
이를 AuthenticationManager 에 전달하고, AuthenticationProvider 에서 인증을 진행합니다. 이때 유저 정보를 DB에서 불러오기 위해서 UserDetailsService 인터페이스를 사용하게 됩니다.
간단하게 설명하자면 Authentication에는 두가지 목적이 있습니다.
Authentication은 다음 4가지를 포함합니다.
그리고 isAuthenticated(인증여부) 까지 총 4가지를 가지고 있습니다.
이 인터페이스는 ProviderManager 가 구현하고 있습니다.
이 구현체의 역할은 AuthenticationProvider 들을 가지고 있고, 이 provider 들을 순회하면서 null 또는 Exception 이 아닌 값이 나올 때까지 동작합니다.
값이 나왔다면 Authentication 객체에서 비밀번호만 지우고 반환하게 됩니다.
provider 는 AuthenticationManager 에서 호출하여 진짜 인증을 할 때 사용합니다.
authenticate 메서드를 통해 인증을 하고, supports 메서드를 통해 해당 타입의 Authentication을 통해 인증가능한지 boolean 으로 리턴합니다.
(Authenticaiton 인증이 아니라 다른 인증방법이 있을 시 오버라이드하여 사용)
public interface AuthenticationProvider {
// Authentication 에 대해 인증을 진행한다.
// ProviderManager(AuthenticationManager) 에서 루프를 돌면서 호출함
Authentication authenticate(Authentication authentication) throws AuthenticationException;
// 이 Authentication 이 처리 가능한지 알려주는 메서드
// 이 또한 ProviderManager 에서 호출한다.
boolean supports(Class<?> authentication);
}
DaoAuthenticationProvider 를 보면 AuthenticationProvider 를 구현하고 있습니다.
DaoAuthenticationProvider 에서 다양한 메서드가 있는데
추상 클래스에 있는 authenticate 메서드가 실질적인 인증을 담당합니다.
//추상 클래스 상속
public class DaoAuthenticationProvider
extends AbstractUserDetailsAuthenticationProvider
//추상 클래스는 인터페이스 구현
public abstract class AbstractUserDetailsAuthenticationProvider
implements AuthenticationProvider, InitializingBean, MessageSourceAware
이때 구현체에서 구현하는 retrieveUser 메서드를 통해 DB에서 유저 정보를 가져오게 되는데 이때 사용하는 메서드가 loadUserByUserName 메서드입니다.
따라서 우리는 UserDetailsService 를 구현하는 구현체를 만들어 등록하면 됩니다.

