스프링 시큐리티에서 인증예외가 발생하면 Http403ForbiddenEntryPoint
에 의해 아무런 메세지 없이 403
상태코드만 반환하게 된다.
프로젝트의 예외처리를 @ControllerAdvice
를 이용하고 있었는데 인증예외의 경우 Filter에서 발생하는 예외이기 때문에 @ControllerAdvice
는 이러한 예외를 포착할 수 없다.
인증예외를 처리해주기 위해서는 AuthenticationEntryPoint
를 커스텀하여 핸들러로 등록해 주어야 한다. (인가예외의 경우에는 AccessDeniedHandler
을 사용한다.)
내가 작성한 AuthenticationEntryPoint
이번 프로젝트는 Jwt인증 방식을 사용하고 있기 때문에 JwtAuthenticationEntryPoint
로 작성해 주었다.
@Slf4j
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
setResponse(response, "인증정보가 없습니다.");
}
private void setResponse(HttpServletResponse response, String message) throws IOException {
log.error("[exceptionHandle] AuthenticationEntryPoint = {}", message);
StatusCode statusCode = StatusCode.UNAUTHORIZED_USER; //401
ObjectMapper objectMapper = new ObjectMapper();
response.setStatus(statusCode.getHttpStatus().value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("utf-8");
StatusResponseDto statusResponseDto = StatusResponseDto.builder()
.statusCode(statusCode)
.message(message)
.build();
response.getWriter().write(objectMapper.writeValueAsString(statusResponseDto));
}
}
AuthenticationException
이 발생할 경우 commence()
가 실행된다.
commence()
가 실행되면 이번 프로젝트의 공통예외 응답으로 작성해둔 StatusResponseDto
의 형식과 401
로 response를 내려주도록 하였다.
AuthenticationEntryPoint
작성후에는 SecurityConfig
에서 핸들러로 등록해주어야 한다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.and()
.exceptionHandling()
.authenticationEntryPoint(new JwtAuthenticationEntryPoint)
...(중략)
}
핸들러 등록후 인증예외가 발생했을 때 401
과 함께 다음과 같은 response가 내려진다!
{ "statusCode" : "UNAUTHORIZED_USER", "message" : "인증정보가 없습니다." }