본문 바로가기
Cloud | CICD/Deploy

[Cors] Cors 에러 삽질 기록

by seoyamin 2023. 3. 7.

드디어 배포된 스프링 부트 API를 프론트팀이 연결하는 과정이었다.

그런데 계속 Cors 에러가 떴다.

엄청난 시간동안 머리를 싸맸는데 결론은 시시콜콜한 문제였다.

영광의 삽질을 기록한다.

 

1. 이름만 같은 CorsFilter, 넌 누구냐 임마

내 프로젝트는 CorsConfig에서 CorsFilter를 정의해서 사용했다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowCredentials(true);
        configuration.addAllowedOrigin("*");
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");

        source.registerCorsConfiguration("/**", configuration);
        return new CorsFilter(source);
    }
}

 

그런데 프론트에서는 계속 Cors에러가 나고, 상황 자체가 내 CorsConfig와 너무 달랐다.

즉, CorsConfig가 안먹히고 있다는 의미였다.

원인을 찾아다니던 중, 내 SecurityConfig에 낯선 CorsFilter가 들어앉아 있는 것을 잡아냈다.

import org.springframework.web.filter.CorsFilter;   ??????

import org.springframework.web.filter.CorsFilter;  // ????

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CorsFilter corsFilter;   // 뉘슈?

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .addFilter(corsFilter)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }
}

 

결국 내가 만든 CorsConfig의 CorsFilter로 정확히 넣어주니까 정상적으로 CorsFilter가 작동했다.

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CorsConfig corsConfig;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .addFilter(corsConfig.corsFilter())   // 내 corsFilter !
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }


}

 

 

2. PreFlight 설정

아직 PreFlight에 대하여 정확히 공부하지는 못했지만, 대략적인 개념만 알아보게 되었다.

프론트가 서버로 요청을 보내기 전, OPTION으로 테스트 요청을 먼저 보내보고 그 요청이 정상처리되면 진짜 요청을 보내는 과정이라고 한다.

따라서 Spring Security에서 Method (GET, POST 등)에 OPTION을 추가해주고, isPreFlight 요청은 무조건 permitAll 해주었다. 

// SecurityConfig

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .csrf().disable()
            .formLogin().disable()
            .httpBasic().disable()
            .addFilter(corsConfig.corsFilter())
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    http.authorizeRequests()
            .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()  // 추가
            .antMatchers(HttpMethod.OPTIONS).permitAll()                 // 추가
    .
    .
    .
        

}