@EnableWebSecurity에 의해 스프링 시큐리티 필터가 스프링 필터 체인에 등록된다.
BCryptPasswordEncoder는 String으로 되어있는 패스워드를 암호화해준다.
이를 빈으로 등록했기 때문에 스프링 컨테이너 안에서 Autowired나 생성자 주입 등으로 자유롭게 주입해서 쓸 수 있다.
WebSecurityConfigurerAdapter에서 Override한 configure()를 이용하여 인증, 인가를 설정할 수 있다.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder(); //<- 비밀번호 암호화를 해준다.
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();//<-사이트간 위조 방지 disable
http.authorizeRequests()
.antMatchers("/api/diary/**").authenticated()// api/diary/ 로 시작하는 url 은 인증 필요
.anyRequest().permitAll() // 그외에는 다 허용
.and()
.formLogin()// 로그인이 필요하면
.loginPage("/loginForm");// loginForm 뷰로 이동.
}
}
url이 “/join”이고 post 요청이면, 회원 가입 dto 내의 패스워드를 BCryptPasswordEncoder에 의해 암호화한다. 저장이 완료되면 로그인 폼으로 다시 리다이렉트한다.
단, join()에서 이미 있는 엔티티인지 확인하는 로직이 없기 때문에 키 제약 위반 등의 예외가 발생한다.
@Controller
public class LoginController {
private final WriterService writerService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
public LoginController(WriterService writerService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.writerService = writerService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
@PostMapping("/join")
public String join(UserJoinRequestDTO dto) {
logger.info("writer join");
String encodedPassword = bCryptPasswordEncoder.encode(dto.getPassword());
writerService.saveWriterWithSecurity(dto.getName(), dto.getEmail(), encodedPassword, Role.User);
return "redirect:/loginForm";
}
}
아래는 실제 mysql에 저장된 테스트 결과다.
패스워드가 암호화된다.
인증되지 않았을 때의 상태인 403 에러(Forbidden)를 캐치하는 메서드를 추가하였다.
@ControllerAdvice
public class GlobalExceptionHandler {
//허가되지 않은 접근일때 캐치
@ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler(AccessDeniedException.class)
public ModelAndView handle403() {
logger.info("not authorized");
return new ModelAndView("403");
}
}