[이슈해결] CORS with Spring (MVC, Security)

MinSeong Kang·2022년 8월 29일
1

이슈해결

목록 보기
3/12

최근 프론트엔드와 협업하는 과정에서 CORS 에러가 발생했다. 쉽게 해결될 줄 알았지만, 총 18번의 시도를 통해 해결할 수 있었다. 원인부터 알아보면, react를 사용하는 프론트쪽에서 withCredentials : true 옵션을 주고 요청을 보냈으나 API 서버에서는 Access-Control-Allow-Credentials : true 를 처리해주지 않았다. 서로 CORS에 대한 정확한 이해없이 구글링을 통해 해결하려도 보니 발생한 이슈였다. 또한 MVC에서 CORS 설정을 해주어야 하는지 Security에서 CORS 설정을 해주어야 하는지 정확히 알지 못한 채, 급한대로 코드를 작성한 것도 이슈의 원인이었다. 따라서 이번 포스팅을 통해 간단히 CORS의 개념을 정리하고, Spring MVC, Security에서 CORS를 설정하는 방법을 기록하려고 한다.!


CORS ?

Cross-Origin Resource Sharing의 약자로, 해석하면 교차 출처 리소스 공유으로, 한 출처에서 실행중인 웹 애플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 정책이다.

여기서 출처란 프로토콜 + 도메인 + 포트를 말하며, 이 중 하나라도 다르다면 cross-origin이라고 한다.

브라우저는 보안적인 이유로 cross-origin HTTP 요청을 제한한다. 따라서 cross-origin 요청을 하려면 서버의 동의가 필요하다. 이 때 서버 쪽에서 cross-origin 요청을 동의하거나 동의하지 않는 메커니즘을 HTTP header를 통해 이루어지는데, 이를 CORS 라고 부른다.

브라우저는 보안적인 이유로 동일한 출처에서만 리소스를 주고 받도록 하는 SOP(Same Origin Policy) 정책이 존재한다. 하지만 CORS 설정을 통해 출처가 다르더라도 리소스를 요청할 수 있다.


CORS with Spring MVC

spring MVC에서 CORS를 설정하는 방법은 크게 2가지가 있다.

  1. 부분적으로 컨트롤러에 CORS를 설정하는 방법

    간단하게 각 컨트롤러에 @CrossOrigin 애노테이션을 추가하여 CORS 설정을 적용할 수 있다.

  2. 전역적으로 Spring MVC 설정에서 CORS를 설정하는 방법

// XXXApplication.java
@SpringBootApplication
public class XXXApplication {

	public static void main(String[] args) {
		SpringApplication.run(XXXApplication.class, args);
	}

	@Bean
	public WebMvcConfigurer corsConfigurer() {
		return new WebMvcConfigurer() {
			@Override
			public void addCorsMappings(CorsRegistry registry) {
				registry.addMapping("/**")
						.allowedOrigins("*")
						.allowedMethods("GET", "POST", "PUT", "DELETE")
						.allowedHeaders("*")
						.allowCredentials(true)
						.maxAge(3000);
			}
		};
	}
}

만일 credentialed request가 아닐 경우, allowCredentials(true) 부분을 제거해야한다.


CORS with Spring Security

// CorsConfig.java

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**",config);
        return new CorsFilter(source);
    }
}
// SecurityConfig.java
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final JwtTokenProvider jwtTokenProvider;
    private final CorsConfig corsConfig;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()

                .authorizeRequests()
                .antMatchers("/*/login", "/*/login/**", "/*/signup", "/*/signup/**").permitAll()
                .anyRequest().hasRole("USER")

                .and()
                .addFilter(corsConfig.corsFilter()) // ** CorsFilter 등록 **
                .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), 
                		UsernamePasswordAuthenticationFilter.class);
        return httpSecurity.build();
    }
    
   // 생략

Spring Security 사용시 CORS 설정을 하기 위해서 Authentication Filter 인증보다 앞에 필터를 추가해주어야 한다.
마찬가지로 만일 credentialed request가 아닐 경우, config.setAllowCredentials(true) 부분을 제거해야한다.


참고문헌

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

0개의 댓글