barded
[어디가게] Spring Security단에서 발생하는 Exception의 처리 불가능 본문
현재 GlobalExceptionHandler
를 통해 컨트롤러단에서 발생하는 에러는 전역적으로 처리가 되어있다.
@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()));
}
@ExceptionHandler(BaseException.class)
public ResponseEntity<ErrorResponse> handleBaseException(BaseException e) {
return ResponseEntity.status(e.getStatus()).body(new ErrorResponse(e.getStatus(), e.getCode()));
}
}
그러나 Spring Security
에서 발생하는 에러는 이러한 ExceptionHandler
가 처리할 수 없다.
그 이유를 알기 위해서는 스프링 시큐리티의 작동 순서를 알아야 한다.
Spring Security의 구조를 확인해보면 Filter에서 발생한 예외는 @ControllerAdvice의 적용범위 밖이기 때문이다.
즉 예외를 Filter Chain
에서 처리하여 Servlet
단에 넘겨줘야 한다고 한다.
기본적으로 Spring Security의 예외는 EntryPoint에서 처리한다.
따라서 이 EntryPoint를 커스텀 구현하여 예외를 처리하도록 해보자.
JwtAuthenticationEntryPoint
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
String code = (String)request.getAttribute("exception");
if (StringUtils.hasText(code)) {
setResponse(response, ErrorCode.UNAUTHORIZATION);
}
}
private void setResponse(HttpServletResponse response, ErrorCode code) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(code.getStatus());
response.getWriter()
.write(objectMapper.writeValueAsString(new ErrorResponse(code.getStatus(), code.getCode())));
}
}
header
에서 “exception
” 필드가 있는 경우에 response
에 직접 값을 써 준다.
JwtFilter
@Slf4j
@RequiredArgsConstructor
public class JwtFilter extends OncePerRequestFilter {
...
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
if (StringUtils.hasText(jwt) && jwtProvider.validateToken(jwt)) {
Authentication authentication = jwtProvider.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (BaseException e) {
//에러 발생시 request header에 에러 등록
request.setAttribute("exception", e.getCode());
}
filterChain.doFilter(request, response);
}
...
}
JwtFilter
에서 토큰을 검증할 때 오류가 있는 경우 request
에 “exception
” 필드를 추가하여 처리한다.
위처럼 처리하면 일반 에러처럼 똑같은 에러 응답이 날라간다.
'프로젝트 > 어디가게' 카테고리의 다른 글
[어디가게] 컨트롤러에서 여러 서비스를 불러야 하는경우 (0) | 2024.03.18 |
---|---|
[어디가게]Spring Security단에서 OPEN-SESSION-IN-VIEW 영속성 컨텍스트 (0) | 2024.03.18 |
[어디가게]UserDetails에 저장하는 정보 및 유니크한 프라이머리키와 유니크한 컬럼 간의 쿼리 속도 (0) | 2024.03.18 |
[어디가게] @AuthenticationPrincipal 및 Custom Annotation을 사용하여 로그인한 사용자 정보 가져오기 (0) | 2023.12.12 |
[어디가게] 사용자의 역할을 구분하면서 생기는 문제에 대한 테이블 설계 방안 (0) | 2023.11.30 |