Cloud, Infra/Deploy

[Cors] Cors 에러 삽질 기록

seoyamin 2023. 3. 7. 23:40

드디어 배포된 스프링 부트 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()                 // 추가
    .
    .
    .
        

}