Security Filter Chain에 등록된 authorization에 맞지 않는 client request가 들어왔을 때, 내가 해당 요청을 핸들링 하고 싶었다.
Spring에서 상식적(?)으로 알려진 Exception 처리 방법이다..
@ControllerAdvice
@Slf4j
public class GreenFarmExceptionHandler {
@ExceptionHandler(Exception.class)
public String handleException(
Exception e,
HttpServletRequest request,
Model model) {
log.info("!! Unknown error! URL: {}, Stack Trace: {}",
request.getRequestURI(),
e.getStackTrace());
model.addAttribute("error",
GreenFarmErrorResponse.builder()
.errorName(e.getLocalizedMessage())
.detailMessage(e.getMessage())
.build());
return "error.html";
}
}
위와같은 @ControllerAdvice + @ExceptionHandler 조합의 예외 처리 방법은 스프링 내부에서 던져지는 예외를 처리할 수 있지만 스프링 영역의 서블릿으로 들어오기 전 filter 단계의 예외는 처리해주지 못한다.
Spring Security의 Exception은?
spring security 기능단에서 던져지는 AuthenticationException, AccessDeniedException 등의 예외들은 request가 서블릿에 도달하기 전 authentication filter에서 생성된다. 그렇기 때문에 위에 설명했던 방식으론 예외처리가 되지 않고, 예외를 거르고 에러 response를 구성하는 custom filter을 implement해야한다.
@Component
@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException, ServletException {
log.error(request.getUserPrincipal().getName().toString()+ "의 "+
request.getRequestURI() + " 접근 거부!");
response.sendRedirect("/e/access-denied");
}
}
직접 Servlet response 객체의 header와 body를 직접 작성할 수도 있지만 나같은 경우에는 그냥 편하게 /e/access-denied 경로로 리다이렉팅하는 방법을 택했다.
@Controller
@RequestMapping("e")
@RequiredArgsConstructor
@Slf4j
public class ErrorController {
@GetMapping("/access-denied")
public void throwAccessDeniedException() {
throw new GreenFarmException(GreenFarmErrorCode.ACCESS_DENIED);
}
}
/e로 시작하는 경로의 요청을 받는 ErrorController을 따로 작성해서.. 여기서 Exception Throwing 했다.
이제 가장 위에 코드로 올린 내 Exception Handler가 Exception을 잘 받아줄 것이다.
Security Filter Chain에 등록된 authorization에 맞지 않는 client request가 들어왔을 때, 내가 해당 요청을 핸들링 하고 싶었다.
Spring에서 상식적(?)으로 알려진 Exception 처리 방법이다..
@ControllerAdvice
@Slf4j
public class GreenFarmExceptionHandler {
@ExceptionHandler(Exception.class)
public String handleException(
Exception e,
HttpServletRequest request,
Model model) {
log.info("!! Unknown error! URL: {}, Stack Trace: {}",
request.getRequestURI(),
e.getStackTrace());
model.addAttribute("error",
GreenFarmErrorResponse.builder()
.errorName(e.getLocalizedMessage())
.detailMessage(e.getMessage())
.build());
return "error.html";
}
}
위와같은 @ControllerAdvice + @ExceptionHandler 조합의 예외 처리 방법은 스프링 내부에서 던져지는 예외를 처리할 수 있지만 스프링 영역의 서블릿으로 들어오기 전 filter 단계의 예외는 처리해주지 못한다.
Spring Security의 Exception은?
spring security 기능단에서 던져지는 AuthenticationException, AccessDeniedException 등의 예외들은 request가 서블릿에 도달하기 전 authentication filter에서 생성된다. 그렇기 때문에 위에 설명했던 방식으론 예외처리가 되지 않고, 예외를 거르고 에러 response를 구성하는 custom filter을 implement해야한다.
@Component
@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException, ServletException {
log.error(request.getUserPrincipal().getName().toString()+ "의 "+
request.getRequestURI() + " 접근 거부!");
response.sendRedirect("/e/access-denied");
}
}
직접 Servlet response 객체의 header와 body를 직접 작성할 수도 있지만 나같은 경우에는 그냥 편하게 /e/access-denied 경로로 리다이렉팅하는 방법을 택했다.
@Controller
@RequestMapping("e")
@RequiredArgsConstructor
@Slf4j
public class ErrorController {
@GetMapping("/access-denied")
public void throwAccessDeniedException() {
throw new GreenFarmException(GreenFarmErrorCode.ACCESS_DENIED);
}
}
/e로 시작하는 경로의 요청을 받는 ErrorController을 따로 작성해서.. 여기서 Exception Throwing 했다.
이제 가장 위에 코드로 올린 내 Exception Handler가 Exception을 잘 받아줄 것이다.