기존 프로젝트에서 스프링 시큐리티 사용에 있어, 인가 실패 시
스프링이 제공하는 기본 예외를 반환하고 있어, 내가 원하는 Json 형태로의 반환을 위해 추가로 커스텀이 필요했다.
당연히 스프링 시큐리티에서 예외처리 커스텀이 가능한 기능을 지원하고 있다.
AccessDeniedHandler 인터페이스를 구현받고 handle 메소드를 재정의 한 후,
시큐리티 설정에 추가해주면 된다.
우선 Jwt와 시큐리티 예외처리를 동일한 형식으로 처리하기 위한 Response Writer 용 static method를 만들었다.
public class CommonWriter {
private static String convertToJson(Object object) {
try {
return new ObjectMapper().writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new IllegalStateException("Could not convert object to JSON", e);
}
}
public static void exceptionWriter(HttpServletResponse response, Exception exception) throws IOException {
final ExceptionType type;
if (exception instanceof AuthenticationException) {
type = ExceptionType.NOT_AUTHORIZED_TOKEN;
} else if (exception instanceof AccessDeniedException){
type = ExceptionType.ACCESS_DENIED;
} else {
type = ExceptionType.UNKNOWN_EXCEPTION_TYPE;
}
Map<String, Object> errorDetails = new HashMap<>();
errorDetails.put("statusCode", type.getStatus().value());
errorDetails.put("status", type.getStatus().name());
errorDetails.put("errorCode", type.getErrorCode());
errorDetails.put("message", type.getMessage());
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(convertToJson(errorDetails));
}
}
그 후 AccessDeniedHandler를 구현한 Custom 클래스를 만들고 Writer를 호출한다.
아래와 같이 handler 메소드에서 exceptionWriter를 호출했다.
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
CommonWriter.exceptionWriter(response, accessDeniedException);
}
}
exceptionWriter에서는 jwt 토큰인증 에러와 스프링 시큐리티 예외에 대한 Exception 인스턴스를 구분하여,
미리 지정해 둔 예외를 반환하도록 처리하였다.
그 후 Security의 설정(filterChain) 메소드에 추가해준다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler) //추가된 부분
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
UsernamePasswordAuthenticationFilter.class);
return http.build();
}
exceptionHandling().accessDenieHandler()에서 정의한 부분을 추가해준다.
이후로 @ControllerAdvice로 요청 예외를 처리할 수 없는 인스턴스에 대한 처리는 exceptionWriter를 통해 수행할 수 있을 것으로 보인다.
'개발 > Spring' 카테고리의 다른 글
[Spring] @RequestParam / @ModelAttribute / @RequestBody / @Requestpart (0) | 2023.07.22 |
---|---|
[Spring] @Configuration, @Bean 으로 의존성 주입(DI) 하기 (0) | 2023.07.16 |
[Spring] Security와 Jwt 사용을 통한 인증, 인가 도입기 (0) | 2023.06.25 |
[Spring] Bean을 Collection으로 호출하기 (0) | 2023.05.21 |
[Spring] Security 정리(1) (0) | 2022.05.15 |