[Spring boot] CORS 해결하기

peace w·2024년 11월 28일
post-thumbnail

프론트엔드와 API 통신을 하면서 CORS 를 많이 겪었다. 혼자서 테스트할 땐 포스트맨으로는 잘 동작하던 API였는데, 프론트에서 받을 때마다 CORS 정책에 위배된다면서 연결이 되지 않았다.

프론트와 협업하는 것도 처음이라 아무것도 모르는 상태였기에 해결하는 데 제법 오랜 시간이 걸렸다.

CORS 란?

CORS ( Cross-Origin Resource Sharing )는 서버가 브라우저가 로딩 리소스를 허용해야 하는 자체 출처가 아닌 다른 출처 (도메인, 스킴 또는 포트)를 나타낼 수 있도록 하는 HTTP 헤더 기반 메커니즘
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

우리가 겪는 CORS 이슈는 모두 이 메커니즘을 위반했기 때문에 발생한다. 번거롭긴 하지만 CORS 덕분에 우리가 주고받는 리소스가 안전하다는 최소한의 보장을 받을 수 있다.

Cross-Origin

브라우저는 보안상의 이유로 cross-origin HTTP 요청을 제한한다. 여기서 cross-origin이란 다른 출처를 의미한다. 즉, 다른 출처로부터의 리소스 요청을 제한하고 동일한 출처에서만 리소스 요청이 가능하다는 것이다.


https://developer.mozilla.org/ko/docs/Learn/Common_questions/Web_mechanics/What_is_a_URL

전체 URL에서 Scheme, Domain, Port만 동일하면 된다.

프론트엔드와 백엔드가 협업하는 경우, 각자 서버를 띄우게 되면 포트가 3000/8000으로 서로 다르다. 서로 다른 서버에서 리소스를 주고 받으려하기 때문에, CORS 이슈가 발생하는 것이다.

※ postman에서는 동작하는 이유
origin이 다른지 판단하는 것은 브라우저다. 서버는 cors를 위반하더라도 정상적으로 응답을 해준다. 응답의 파기 여부는 브라우저에 의해 결정된다. 즉, 브라우저는 통하지 않는 통신인 postman에서는 정상동작한다.


해결방법

Spring Security를 사용중이었기에 filterChain 메서드에 cors 관련 설정을 추가했다.

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.httpBasic(HttpBasicConfigurer::disable) // HTTP 기본 인증 비활성화
                .formLogin(AbstractHttpConfigurer::disable) // httpBasic 인증 방식 사용 x
                .csrf(AbstractHttpConfigurer::disable) // csrf 비활성화
                .sessionManagement(httpSecuritySessionManagementConfigurer -> httpSecuritySessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

                .cors(corsCustomizer -> corsCustomizer.configurationSource(request -> {
                    CorsConfiguration config = new CorsConfiguration();
                    config.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
                    config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH"));
                    config.setAllowCredentials(true);
                    config.setAllowedHeaders(Arrays.asList("Authorization", "Authorization-refresh", "Cache-Control", "Content-Type"));
                    config.setExposedHeaders(Arrays.asList("Authorization", "Authorization-refresh"));
                    config.setMaxAge(3600L); // 1시간
                    return config;
                })) // cors
                ;

        return http.build();
    }

  • setAllowedOrigins() : 허용할 URL
  • setAllowedMethods() : 허용할 Http Method
  • setAllowCredentials() : 쿠키 인증 요청 허용
  • setAllowedHeaders() : 허용할 Header
  • setExposedHeaders() : 응답할 Header
  • setMaxAge() : 허용 시간

맨 처음에는 setAllowedOrigins() 메서드를 제외하고 전부 "*" 와일드카드를 사용해서 전부 허용했었다.

그래도 안 되길래 구글링해보니 setAllowCredentials() 메서드를 true로 설정한 경우에는 와일드카드를 사용하면 안 된다는 얘기가 있길래, 값을 전부 수정했다.

그리고 WebConfig 에도 cors 설정을 적어주었다.

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("https://localhost:3000");
    }
}

이렇게 설정을 바꿔주니 정상적으로 api 통신이 가능했다!

profile
더 성장하자.

0개의 댓글