Spring boot 3.0.6, Spring security 6, jwt적용 및 인증, 예외 처리

박은빈·2023년 4월 27일
0

에러

목록 보기
4/5

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에러가 아닌 내가 커스텀한 에러가 나오게 된다.

그리고 이전에 동작하지 않던 테스트도 다시 해보니 정상적으로 동작했다

profile
안녕하세요

0개의 댓글

관련 채용 정보