새로운 팀 프로젝트에 합류해서 코드를 작성하며 진행을 하고 있었다.
그런데, swagger로 엔드포인트를 테스트 하던 도중, 오류가 발생했는데 내가 원하는 response가 아니라 CORS 에러 같은 알 수 없는 오류가 발생하는 것을 확인하였다.
해당 코드는 단순히 유저의 내용을 변경하는 코드인데, 예외 테스트를 할 때 일부러 Json이 파싱되지 않게 넣었다.
당연히 예상 결과는 400 Bad Request가 발생해야 한다고 생각했는데 위처럼 아예 실패라는 결과를 얻게 되었다..
이유가 뭔지 궁금해서 스프링의 로그를 확인해보니
위 사진과 같은 형태로 에러 발생 후에도 계속해서 JWT 검증 필터에 접근하는 현상을 확인할 수 있었다.
ExceptionHandler을 사용해서 처리하면 되는 부분 아닌가?
사실 이 문제는 Json 파싱 에러이기 때문에 인증과는 별개라고 생각해서 ExceptionHandler을 적용해보았다.
당연히, 결과는 잘 나오게 되었는데 어째서 이러한 문제가 발생했는지가 궁금했다.
문제의 원인을 찾아보자
먼저 Debug모드로 실행하여 검증 필터의 맨 윗부분과 FilterChainProxy의 doFilter 부분에서 확인을 해보았다.
위 두개의 사진에서, 한 번 검증필터를 지나갔음에도 다시 JwtAuthenticationFilter로 접근하는 것을 확인할 수 있었다.
내가 작성한 검증 필터 코드가 아니기 때문에 필터 부분에서 문제가 있는 것은 아닐까? 체크를 하며 진행을 했고, 필터의 로직상에서는 크게 문제가 없는 것으로 생각되었다.
또한 OncePerRequest 필터를 상속받았기 때문에 한 번의 요청에 한 번만 실행되게 설정되어 있었다.
그렇다면 생각할 수 있는 다른 원인은?
위 두 개의 부분을 고려해보았을 때, 아무래도 요청이 여러 번 들어오는 것이 문제가 되지 않을까 싶어 검증 필터부분에 요청 Url과 method을 확인해봤다.
세상에.. 분명 나는 /profile/address 에 PATCH 요청을 하나만 보냈을 뿐인데, 왜인지 /login이라는 url에 PATCH 요청이 계속해서 오는 것을 확인할 수 있었다.(아무래도 계속해서 요청이 들어오는 데, 무한 루프에 빠지는 것을 방지하기 위해 일정 시간이 지연되어 스프링에서 자체적으로 응답을 종료시킨 것 같다)
/login url이 대체 왜 들어오는 것일까?
다시 한 번 확인해본 결과, 우리 엔드포인트에는 /users/login은 존재해도, /login이라는 엔드포인트는 존재하지 않는다. 그렇다면 가장 의심이 되는 부분은 Spring Security 쪽이라고 생각되었다.
파악해 본 결과 문제의 흐름은 다음과 같았다.
- 인증이 필요한 요청이 들어와 JWT 검증 필터를 한 번 지나게 된다.
- 컨트롤러로 진입하는 과정에서 Request의 Json 파싱이 제대로 되지 않아 HttpMessageNotReadableException이 발생한다.
- 스프링 시큐리티에서 인증되지 않은 요청으로 파악해 인증 실패로 처리하고 /login으로 리다이렉션 시킨다.
- /login url을 통해 JWT 검증 필터로 들어오게 된다.
- 하지만 /login은 .anyRequest.authenticated() 으로 인증되어야 하기 때문에 오류가 발생해 다시 /login으로 리다이렉션 시킨다.
- 반복..
의 과정을 거치게 되는 것 같다. 여기서 궁금한 점은, /login 으로 한 번 오는 것은 이해가 되지만 그 다음에 어떤 오류가 발생했길래 다시 /login 요청을 보내게 되는지는 파악하지 못했다.
이제 해결해보자
해결 방법은 간단했다.
.exceptionHandling(exception ->
exception
.authenticationEntryPoint(authenticationEntryPoint()));
을 통해서, 인증되지 않은 요청일 때 exception 포인트를 지정해주면 되는 것이었다.
위에 작성했던 ExcpetionHandler을 설정하지 않았을 때, 오류가 발생해 인증되지 않은 요청이 온다면
401에러를 발생시켰다. 물론 이 응답은 내가 원하는 결과가 아니기 때문에 ExceptionHandler을 설정하는 것 또한 같이 해주게 되었다.
하지만, 추후 다른 오류로 인해 같은 문제가 발생할 수도 있기 때문에 파악을 해보고 싶었다.
'Back-End > Spring' 카테고리의 다른 글
스프링 프레임워크 따라해보기 - 컨트롤러 매핑과 응답 전송 (0) | 2024.10.11 |
---|---|
스프링 프레임워크 따라해보기 - 웹 서버 구축 (1) | 2024.10.10 |
[Spring] Spring Security를 이용한 우당탕탕 인증/인가 개발기(1) - 회원가입(일반/Oauth2.0) (0) | 2023.12.21 |
[Spring] Oauth2.0과 Spring Security 작동원리(+ 42Seoul Api를 이용한 Oauth2.0 로그인 구현) (0) | 2023.11.24 |
[Spring] Spring의 기본적인 구조는 어떻게 생겼을까? (0) | 2023.11.07 |
댓글