Spring Security - UserDetails, UserDetailsService
2022. 7. 7. 16:04
반응형
UserDetails
- 스프링 시큐리티가 사용자 정보를 알 수 있도록 사용자에 대한 정보를 저장하는 인터페이스이다.
- 즉 스프링 시큐리티가 개발자 대신에 내부적으로 사용자 정보를 알 수 있도록 UserDetails 인터페이스를 상속받아서 스프링 시큐리티가 필요한 정보들을 구현해야한다.
다음과 같이 User 클래스에 UserDetails를 상속받아서 시큐리티가 필요한 정보를 구현할 수 있다. 이렇게 설정을 하면 스프링 시큐리티는 사용자를 시큐리티 정보에 구성하기 위한 최소한의 정보를 내부적으로 저장하게 된다.
@Entity
@Getter
public class User implements UserDetails {
@Id @GeneratedValue
private Long id;
private String username;
private String password;
//사용자에게 부여된 권한을 지정한 컬렉션으로 반환
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
//계정이 만료되지 않았는가?
@Override
public boolean isAccountNonExpired() {
return true;
}
//계정이 잠금상태가 아닌가?
@Override
public boolean isAccountNonLocked() {
return true;
}
//비밀번호가 만료되지 않았는가?
@Override
public boolean isCredentialsNonExpired() {
return true;
}
//계정이 활성화 되었는가?
@Override
public boolean isEnabled() {
return true;
}
}
UserDetailsService
- 사용자가 로그인을 할 때 기본 회원인지 인증하고, 인증이 완료되면 로그인한 상태의 사용자의 세션을 유지시켜주기 위한 인터페이스이다.
- 기본적으로 해당 인터페이스를 상속받으면 loadUserByUsername 메서드를 구현해야 한다.
- loadUserByUsername 메서드는 현재 시큐리티를 통해서 로그인한 회원이 기본 회원인지 아닌지 인증하는 메서드이다. 파라미터로 넘어온 username은 html form에서는 id 값에 해당하는 정보이고, JSON 데이터에서는 username에 해당하는 value 값이 넘어온다.
- 인증에 성공하면 해당 회원에 대한 세션정보가 생성되고 Authentication 객체나 @AuthenticationPrincipal 애노테이션을 통해서 세션에 들어있는 사용자 정보를 꺼내와 사용할 수 있다. 즉, 이 메서드가 정상적으로 완료되어 UserDetails 정보가 반환되면 인증에 성공한 것이다.
@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("해당 아이디는 존재하지 않습니다."));
}
}
이렇게 구현한 PrincipalDetailsService는 다음과 같이 시큐리티 설정정보 클래스에 등록해야 정상적으로 사용할 수 있다. 빈으로 등록되어있는 UserDetailsService를 주입받고, 주입받은 객체를 rememberMe().userDetailsService(userDetailsService) 로 권한 요청을 넣어주면 된다. rememberMe().userDetailsService(userDetailsService)는 userDetailsService에 의해서 인증된 사용자 정보를 세션에서 기억한다는 뜻이다.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final UserDetailsService userDetailsService;
private static final String[] PUBLIC_ACCESS_URL = {"/", "/login", "/register"};
@Bean
public PasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(PUBLIC_ACCESS_URL)
.permitAll()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/", true)
.and()
.logout()
.logoutSuccessUrl("/")
.and()
.rememberMe()
.userDetailsService(userDetailsService)
.and()
.oauth2Login()
.loginPage("/login")
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer(){
return (web) -> web.ignoring().antMatchers("/images/**", "/js/**");
}
}
반응형