들어가며
이전 포스팅에서 전역 예외 핸들러를 만들어주며, 서비스에서 발생하는 Exception을 처리해주는 과정을 정리해보았습니다. 그러나, 필터에서의 예외는 해당 핸들러로 처리할 수가 없습니다.
따라서, 인가와 인증 과정을 거치는 필터 내에서 발생하는 예외를 처리하는 과정을 다뤄보겠습니다.
❏ 요청과 응답의 과정
먼저, 요청과 응답이 어떠한 과정을 거치는 지부터 간단하게 정리해보겠습니다.
1. 클라이언트로부터 들어온 요청은 Servlet Filter를 거치게 됩니다.
해당 과정을 통해 필요한 수정이나 처리 과정을 거치게 되며, 필터를 통과한 요청은 DispatcherServlet으로 전달되게 됩니다.
2. DispatcherServlet은 클라이언트로부터 들어온 요청을 검사하여 적절한 Controller에 위임하는 역할을 합니다.
따라서, 컨트롤러에서 데이터베이스로부터의 데이터 조회, 비즈니스 로직 수행 등으로 요청을 처리하게 됩니다.
그 후, 컨트롤러로부터 반환된 응답은 DispatherServlet으로, 그리고 클라이언트로 반환되게 됩니다.
❏ ControllerAdvice
ControllerAdvice는 요청을 처리하는 과정에서 발생하는 예외를 처리하기 위해, 특정 예외에 따른 처리 방법을 정의하는 클래스입니다.
< Exception 처리 과정 || ErrorCode, CustomException, ControllerAdvice >
❍ ControllerAdivce에서 예외 처리가 되지 않는다면?
ControllerAdvice는 DispatcherServlet까지 요청이 넘어온 후, 그 후에 요청이 처리되는 즉, 컨트롤러, 서비스, 리포지토리와 같은 과정에서 발생하는 예외만 처리할 수 있습니다.
그렇기에 Filter 단에서 발생하는 예외는 해당 핸들러에서 처리가 이루어지지 않습니다.
❏ 해결 방안
인증과 인가에서 처리하는 과정 중 발생하는 예외를 처리해주기 위하여, AuthenticationEntryPoint와 AccessDeniedHandler를 커스텀하여 구현을 해주었습니다.
❍ AuthenticationEntryPoint
인증이 실패했을 경우의 예외를 처리해주는 핸들러입니다.
@Component
@RequiredArgsConstructor
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final ObjectMapper objectMapper;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
MemberException e = new MemberException(ErrorCode.INVALID_TOKEN);
response.setStatus(e.getErrorCode().getStatus());
response.setContentType(MediaType.APPLICATION_JSON_VALUE+ ";charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(e.getErrorCode().getMsg()));
}
}
❍ AccessDeniedHandler
인가에 실패했을 경우의 예외를 처리해주는 핸들러입니다.
@Component
@RequiredArgsConstructor
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private final ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
MemberException e = new MemberException(ErrorCode.ACCESS_DENIED);
response.setStatus(e.getErrorCode().getStatus());
response.setContentType(MediaType.APPLICATION_JSON_VALUE+ ";charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(e.getErrorCode().getMsg()));
}
}
❏ 정리
- 요청 → Servlet Filter → DispatcherServlet → Controller ...
- ControllerAdive는 DispatcherServlet 이후의 요청 처리 과정에서 발생하는 예외만 처리 가능
- 따라서, FIlter 내에서 발생하는 예외 처리를 위해 커스텀 핸들러를 구현해주었음
요청과 응답이 처리되는 과정을 다시 살펴볼 수 있었으며, ControllerAdvice의 적용 범위에 대해서도 알 수 있었다.
따라서, FIlter 내에서 발생하는 예외를 처리하기 위해 커스텀 핸들링을 하는 과정도 경험해볼 수 있었다.