스프링 시큐리티는 다양한 방식의 인증처리를 제공합니다.
이중에 폼 기반 인증방식을 이용하여 폼을 통해 아이디와 비밀번호를 받고 인증처리는 스프링 시큐리티에게 위임하여 처리하도록 하였습니다.
스프링에서는 기본적으로 폼 기반 인증처리를 지원하기 때문에,
UserDetailsService 인터페이스만 구현하면 된다.
UserDetailsService는 loadUserByUsername을 구현해야 한다.
loadUserByUsername에는 유저로부터 받아온 username을 바탕으로 repository에서 회원을 찾아온 뒤, UserDetails 인터페이스를 구현한 클래스를 반환하여 주면 된다.
그 뒤는 스프링이 아이디와 비밀번호를 검증하여 인증에 성공했다면, authentication 객체를 생성한 뒤 SecurityContext에 넣어준다.
함수형 인터페이스이기 때문에 아래의 코드와 같이 작성할 수 있다.
findByUserId로 username을 바탕으로 회원 엔티티를 찾아온 뒤, DTO 객체로 바꿔주었다.
DTO 객체로 바꾼 뒤에는 UserDetailsService 인터페이스를 구현하는 BoardPrincipal 객체로 바꿔준뒤 반환하였다.
이렇게 구성하면 authentication에 BoardPrincipal 객체가 담겨있게 된다.
또한 passwordEncoder를 통해 비밀번호의 암호화를 위한 인코더 객체를 빈으로 등록하였다.
@Bean
public UserDetailsService userDetailsService(UserAccountRepository userAccountRepository) {
return username -> userAccountRepository.findByUserId(username)
.map(UserAccountDto::from)
.map(BoardPrincipal::from)
.orElseThrow(() -> new UsernameNotFoundException("해당 유저를 찾을 수 없습니다. - username" + username));
}
@Bean
public PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
게시글 등록시에는 회원에 대한 정보가 필요하다.
@AuthenticationPrincipal 애노테이션을 통해 authentication에 등록해 놓았던 UserDetails를 구현한 객체를 가져올 수 있다.
@PostMapping("/form")
public String postNewArticle(
@AuthenticationPrincipal BoardPrincipal boardPrincipal,
ArticleRequest articleRequest) {
articleService.saveArticle(articleRequest.toDto(boardPrincipal.toDto()));
return "redirect:/articles";
}