ahnnyung ,/Spring Rest API

[Spring Rest API] @CrossOrigin을 줬는데도 CORS 에러가 발생할 때 (CORS preflight 오류)

hi,ho 2020. 11. 26. 13:24
반응형

Spring Security를 사용하여 로그인/인증을 구현했다. 로그인을 통해 JWT토큰을 발급해주고 Frontend에서 발급받은 JWT토큰을 헤더에 포함하여 Request를 보내야 JwtAuthenticationFilter를 통해 JWT토큰이 확인되어야 기존 API를 사용할 수 있도록 구현하였다.

 

구현을 완료한 뒤 포스트맨을 통해 테스트해봤을 때는 문제없이 잘 동작했다. 하여 서버로 배포한 뒤 얼마 지나지 않아 Front작업하는 팀원으로부터 CORS에러가 난다는 얘기를 들었다.

 

분명 이전포스팅때의 경험을 살려 다음과 같이 @CrossOrigin어노테이션에 받는 입장의 allowedHeaders로 해당 JWT토큰값을 가지고있는 "X-AUTH-TOKEN"헤더를 추가해줬음에도 에러가 발생하였다.

aloowedHeaders에 "X-AUTH-TOKEN"을 추가해준 모습

 

혹시 몰라서 개별 컨트롤러별로 어노테이션을 주면 일부 누락되는 경우도 발생할 것 같아 해당 어노테이션을 모두 지우고 WebConfiguration을 따로 만들어 적용하였다.

WebConfiguration.java 기존의 Content-Disposition 헤더 문제와 더불어 X-AUTH-TOKEN 헤더에 대해서도 처리를 해뒀음을 볼 수 있다.

 

일단 Frontend를 담당하는 팀원에게 포스트맨으로 해당 헤더를 직접 넣고 API를 호출해보라고 부탁했고, 팀원은 포스트맨으로는 잘 작동된다고 했다. 이때까지만해도 Frontend단의 코드 결함일거라 생각했다. 하지만 계속해서 에러가 발생하였고, 관련문제를 좀 더 찾아보기로했다. 

 

발생한 에러문장은 다음과 같다.

preflight 오류

어라? preflight는 처음보는건데.. 뭐지?? 찾아보니 다음과 같다.

HTTP 스펙에서는 CORS 문제에 대해 정의를 하고 있으며, 크롬, 파이어폭스, IE 등과 같은 대부분의 알려진 브라우저는 이 스펙을 준수하고 있습니다. CORS 상황이 발생했을 때 브라우저는 다음과 같은 절차를 사용합니다.

  • 일반적인 요청에 대해서는 아무런 처리도 하지 않음, 일반적인 요청이라고 하면 다음 사항에 부합되는 요청을 의미함
    • GET, HEAD, POST
    • Request Header에는 다음 속성만 허용:
      • Accept, Accept-Language,  Content-Language,  Content-Type
    • Content-Type은 다음만 허용
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain
  • 이런 일반적인 요청이 아닌 경우 브라우저는 접근할 리소스를 가지고 있는 서버에 preflighted 요청을  보냄
    • preflighted 요청은 특별한 목적을 가지는 요청으로 method = OPTIONS 으로 전송
    • OPTIONS 요청을 받은 서버는 Response Header에 서버가 허용할 옵션을 설정하여 브라우저에게 전달.
    • 브라우저는 서버가 보낸 Response 정보를 이용하여 허용되지 않은 요청인 경우 405 Method Not Allowed 에러를 발생시키고, 실제 페이지의 요청은 서버로 전송하지 않음
    • 허용된 요청인 경우 전송
  •  

CORS 처리 방식

위의 과정을 통해 CORS가 처리되는데 Request Header헤더에 X-AUTH-TOKEN 헤더가 추가된 경우가 바로 일반적인 요청이 아닌 경우에 해당하게 된다.

 

따라서 위 그림의 3번 과정이 행해지게되고 자연스레 그 과정에서 에러가 발생하게 된 것이다. 따라서 OPTIONS 메소드로 날라오는 요청에 대해서는 허용을 해주도록 Filter 옵션을 수정하였다.

 

변경 후 오류는 말끔히 사라졌고, 올바르게 동작했다.

저번도 그렇고 CORS에 대해서 참 여러번 곤욕을 겪는 것 같다. CORS에 대해서도 정리가 필요한 것 같다.

 

 

 

++ 2020.11.27 추가

위와 같은 세팅 이후에도 다음과 같이 에러가 난다면 에러문구에 나와있는 "Content-Type"도 allowedHeaders에 추가해주어야 한다.

여전히 에러가 나는 장면
allowedHeaders안에 "Content-Type"도 추가한 모습

반응형