본문 바로가기
오류노트

Access to XMLHttpRequest at 'http://localhost:8888/api/v1/login' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on ..

by 덩라 2023. 6. 27.

아래 환경에서 개발하다가 로그인 기능을 테스트하는 단계에서 발생한 오류입니다.

Front-End : React (axios 사용) 3000번 포트 서비스
Back-End : Java / Spring 8888 포트 서비스

 

위 에러가 발생한 원인은 웹 상에 존재하는 "동일 출처 정책" 이라는 보안 정책에 위배되는 요청을 보냈기 때문입니다.

아래는 동일 출처 정책에 대한 설명입니다.

 

동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여줍니다.
출처 : https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy

https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy

 

동일 출처 정책 - 웹 보안 | MDN

동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로

developer.mozilla.org

 

즉, 문서나 스크립트 등의 리소스가 "다른 출처" 에서 발생한 요청이 경우, 이를 신뢰할 수 없어 차단하는 정책이라는 의미인데....

좀 더 백엔드 개발에 접목해서 이야기 하자면 아래와 같은 경우를 말합니다.

프론트 엔드 서버에서 백엔드 서버로 요청을 보내는 과정을 표현하자면 아래와 같이 표현할 수 있습니다.

프론트엔드는 ReactJs 로 구현되어 있고, 백엔드는 Java/Spring 으로 구현되어 있습니다.

프론트엔드에서 백엔드로 REST API를 호출하여 응답을 json으로 내려받아 화면에 데이터를 랜더링하는 방식으로 되어있습니다.

 

여기서 문제가 뭘까요?

바로, 백엔드를 서비스하는 URL(http://localhost:8888)과 프론트엔트를 서비스하는 URL(http://localhost:3000)이 다르다는 점입니다.

 

앞서 설명한 "동일 출처 정책" 에 의해 백엔드 서비스에선 자신과 동일한 URL로 들어온 요청만을 받아들이고, 다른 URL은 보안상 문제로 요청을 허용하지 않습니다.

 

그렇기 때문에, 백엔드 서비스에서 "어? 이건 내가 신뢰할 수 없는 URL인데? 접근을 불허한다!" 하고 오류를 뱉는 것 입니다.

 

저 같은 경우에는 Spring 설정을 추가하여 해당 문제를 해결했습니다. 그 설정은 아래와 같습니다.

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private static final String[] WHITE_LIST = {
            "http://localhost:3000"
    };

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins(WHITE_LIST)
                .allowedMethods(
                        HttpMethod.GET.name(),
                        HttpMethod.POST.name(),
                        HttpMethod.PUT.name(),
                        HttpMethod.DELETE.name()
                );
    }
}

@Configuration 어노테이션을 통해, SpringApplication 을 실행할 때, 아래 class 설정을 적용하도록 했습니다.

WebConfig class 는 Spring 에서 지원하는 WebMvcConfigurer 를 상속받고, 수 많은 메서드 중 "addCorsMappings" 메서드를 재정의 했습니다.


해당 메서드에서는 

  1. addMapping : 어떤 URI 에 대해 설정을 적용할 것 인가 (/** 는 모든 URI 에 적용한다는 의미)
  2. allowedOrigins : 어느 요청에 대해 적용할 것인가 (상단에 정의된 WHITE_LIST 배열에 선언된 URL은 허용하겠다는 의미)
  3. allowedMethods : 어떤 HttpMethod 에 대해 적용할 것인가 (GET, POST, PUT, DELETE 메서드에만 적용하겠다는 의미)

를 적용했습니다.

위에서 적용한 3개의 옵션 말고도 많은 옵션을 정의할 수 있습니다. (하지만, 전 간단하게 꼭 필요한 3개만 해봤습니다.)

 

기타 추가적인 설명은 아래 Spring 공식 문서를 참고해주세요.

https://docs.spring.io/spring-framework/reference/web/webmvc-cors.html

 

CORS :: Spring Framework

Spring MVC lets you handle CORS (Cross-Origin Resource Sharing). This section describes how to do so.

docs.spring.io

 

댓글