spring boot 2때 jwt를 사용하고 특정 url에 jwt를 검증하기 위해서는 SecurityFilterChain
에서 authorizeRequests()
를 이용해 antMatcher
로 제어가 가능했다.
그리고 addFilterBefore
를 이용해 필터 적용 전 permitAll()
이나 authenticated()
에 따라서 addFilterBefore
를 통과시킬지 정했었다.
하지만 spring boot 3가 되면서 authorizeRequests()
는 더 이상 사용하지 못하게 되었고 그 대신 authorizeHttpRequests()
를 사용하게 되었다.
하지만 여기서 이전에 사용하던 방법인 addFilterBefore
를 이용할 경우 authorizeHttpRequests()
에 관계없이 무조건 설정한 필터 이전에 동작하게 되기때문에 403이 반환된다.
addFilterBefore
자체가 필터 이전에 동작하는 것이기때문에 거기서 jwt 검증을 하게되면 무조건 에러가 발생 할 수 밖에 없다.
addFilterBefore에서 실행하는 doFilterInternal()메서드에서 특정 url을 포함할 경우 바로 리턴을 하는 코드를 작성했다
private static final List<String> EXCLUDE_URLS = Arrays.asList("/api/v1/users", "/swagger-ui", "/v3/api-docs");
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
if(!shouldExclude(request)) {
//...
}
filterChain.doFilter(request, response);
} catch(JwtException e) {
//...
}
}
private boolean shouldExclude(HttpServletRequest request) {
return EXCLUDE_URLS.stream().anyMatch(url -> request.getRequestURI().contains(url));
}
제외할 url을 배열의 형태로 만들었다.
그리고 그 배열을 stream을 돌면서 request의 url이 배열 안에 있는 url을 포함한다면 바로 필터를 통과시키는 로직을 작성하였다.
이렇게 할 경우 이전에 비해 성능은 살짝 떨어지겠지만 큰 차이가 없을거같고 아직까지 이 방법 외에 다른 방법을 찾지 못했기때문에 나에게는 이 방법이 최선이다.
이제 특정 url을 제외하는 작업을 해 주었으니 jwt검증중에 예외가 발생할 경우 403이 아닌 내가 커스텀으로 작성한 예외를 반환하게 만들것이다
.addFilterBefore(new JwtFilter(jwtUtils), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JwtExceptionHandler(objectMapper), JwtFilter.class)
JwtFilter
에서 처리한다음 다음 예외 전용 JwtExceptionHandler
를 만들어주었다
JwtFilter
에서 예외가 발생할 경우 해당 예외를 담고있는 Filter가 JwtExceptionHandler
로 가게 된다.
그리고 JwtExceptionHandler
에서 다음과 같이 작성해주었다
@Slf4j
@RequiredArgsConstructor
public class JwtExceptionHandler extends OncePerRequestFilter {
private final ObjectMapper objectMapper;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} catch (JwtException e) {
log.info("에러 발생");
response.setStatus(e.getErrorCode().getHttpStatus().value());
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Response failedResponse = Response.failed(e.getErrorCode().getResultCode(),e.getErrorCode().getErrorCode());
response.getWriter().write(objectMapper.writeValueAsString(failedResponse));
}
}
}
예외가 발생했기때문에 catch에서 예외를 잡게 되고
그 예외에서있는 내용을 response에 넣어주었다.
그리고 body도 기존에 예외처리를 하던 방식으로 Response객체를 만들어준다음
objectMapper를 이용해 String으로 변환 후 response에 넣어주었다.
이렇게 할경우 기존 403에러가 아닌 내가 커스텀한 에러가 나오게 된다.
그리고 이전에 동작하지 않던 테스트도 다시 해보니 정상적으로 동작했다