Spring Security 내부 구현체 알아보기 첫 번째 포스팅으로는,
Spring Security에서 사용자를 기술하는 인터페이스인 UserDetailsService
및 UserDetails
와 UserDetailsManager
를 살펴보고자 한다.
먼저 UserDetailsService
는 인증 요청이 AuthenticationProvider
로 흘러들어오게 될때, 사용자의 id와 pw를 확인하기 위해 PasswordEncoder
와 함께 사용된다.
이름에서도 알 수 있듯이 UserDetailsService
는 UserDetails
를 서비스하는 로직이 작성되어있을 것이라고 유추해볼 수 있다.
먼저 UserDetailsService
가 어떤 것이며, 그 안에서 UserDetails
가 어떤 역할을 하는지 알아보자.
UserDetailsService 인터페이스는 다음과 같이 구성되어 있다.
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
UserDetailsService
인터페이스는 오로지 loadUserByUsername()
메서드만 작성되어 있으며, 사용자의 이름(id)로 UserDetails 객체를 반환하는 목적만 가진다.그럼 UserDetails 객체는 어떤 것을 나타내는지 확인해보자.
UserDetails 인터페이스는 다음과 같이 구성되어 있다.
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
여기서 Authority
는 해당 User의 권한을 나타내며, getAuthorities()
메서드를 통해 해당 User의 권한을 가져온다. 그 밖의 메서드들 또한 직관적인 네이밍을 통해 각 메서드들의 역할을 알 수 있다.
UserDetails의 구현체는 getAuthorities()
, getPassword()
, getUsername()
, isAccountNonExpired()
, isAccountNonLocked()
, isCredentialsNonExpired()
, isEnabled()
메서드가 구현되어야 함을 알 수 있다.
isAccountNonExpired()
, isAccountNonLocked()
, isCredentialsNonExpired()
, isEnabled()
메서드는 true를 반환시켜야 한다.
AuthenticationProvider는 인증 로직에서 UserDetailsService를 통해 DB에 저장된 User의 세부정보를 획득한다.
후에 User의 encodedPassword(PasswordEncoder에 의해 암호화되어 DB에 저장되었던 password)와 사용자가 로그인 요청시 입력했던 password가 일치하는지 PasswordEncoder를 이용하여 비교하는 로직을 진행한다.
비교 후 값이 동일할 경우, 결과를 AuthenticationFilter에 전달하고 세부정보(Authentication 객체)가 SecurityContext에 저장된다.
만약 값이 동일하지 않을 경우 일반적으로는 클라이언트에 HTTP 401 status code가 반환된다.