[Spring Boot] CORS(크로스 도메인이슈) 해결하기

Posted by 김성철

SpringBoot - CORS 이슈 해결하기

Cross-Origin Resource Sharing,CORS 란 다른 출처의 자원을 공유할 수 있도록 설정하는 권한임  

Spring Security 참고 URL

https://toycoms.tistory.com/37  
https://velog.io/@chullll/Spring-Security-CORS  

WebConfig 클래스 생성후 아래의 메소드들 추가

기본적인 Default 값은 아래와 같음  
	Allow all origins.  
	Allow "simple" methods GET, HEAD and POST.  
	Allow all headers.  
	Set max age to 1800 seconds (30 minutes).  
  
	- addMapping() 으로 CORS를 적용할 URL 패턴을 정의  
  
	- allowedOrigins() 자원 공유를 허락할 Origin을 지정할수 있음  
		.allowedOrigins("*"); 로 해서 전부다 줄수 있고 아래처럼 특정 URL만 줄수도 있음  
		.allowedOrigins("http://localhost:8080" , "http://localhost:7070");  
  
	- allowedMethods("POST" , "GET") 를 사용하여 허용할 HTTP method 를 지정할 수 있음  
  
	- maxAge(시간) 원하는 시간만큼 pre-flight 리퀘스트를 캐싱 해둘수 있음  
  
	=================================================================================================================  
	@Configuration  
	public class WebConfig implements WebMvcConfigurer {  
  
		@Override  
		public void addCorsMappings(CorsRegistry registry) {  
			registry.addMapping("/**")  
				.allowedOrigins("*")  
				.allowedMethods("POST" , "GET")  
				.maxAge(6000);  
  
		}  
  
	}  
  
	=================================================================================================================  

어노테이션으로 사용하기

메소드나 클래스명 위에 어노테이션으로 쓰면되며  
origins, methods, maxAge, allowedHeaders 옵션을 다 줄수 있음  
=================================================================================================================  
ex)  
	@CrossOrigin(origins="*")  
	public class TestController{  
  
		@CrossOrigin(origins = "*", allowedHeaders = "*")  
		@GetMapping("/userInfo")  
		public String getUserInfo (){  
  
=================================================================================================================  

##################################################################################################################

Spring Security 설정

스프링 시큐리티를 사용한다면 아래와같이 설정을 해줄수가 있다  
WebSecurityConfig 클래스 안에 아래와 메소드를 정의 하고 configure 메소드에 해당 내용을 추가하면 된다  
  
- CORS 설정 메소드 corsConfigurationSource  
=================================================================================================================  
@Bean  
CorsConfigurationSource corsConfigurationSource() {  
	CorsConfiguration configuration = new CorsConfiguration();  
  
	configuration.setAllowedOriginPatterns(Arrays.asList("*"));  
	configuration.setAllowedMethods(Arrays.asList("HEAD","POST","GET","DELETE","PUT"));  
	configuration.setAllowedHeaders(Arrays.asList("*"));  
	configuration.setAllowCredentials(true);  
  
	UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();  
	source.registerCorsConfiguration("/**", configuration);  
	return source;  
}  
  
=================================================================================================================  
  
- corsConfigurationSource 메소드를 적용  
=================================================================================================================  
@Override  
protected void configure(HttpSecurity httpSecurity) throws Exception {  
    // We don't need CSRF for this example  
    httpSecurity  
			.cors().configurationSource(corsConfigurationSource())	//이부분  
			.and()													//이부분 추가, 여기는 뒤에 설정들을 이어서 할수 있도록 해줌  
            .csrf()  
            .disable()  
            // dont authenticate this particular request  
            .authorizeRequests()  
            .antMatchers("/","/csrf","/authenticate","/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**").permitAll()  
            .antMatchers("/user","/user/**").hasRole("ADMIN")  
            // all other requests need to be authenticated  
            .anyRequest()  
            .authenticated()  
            .and()  
            // make sure we use stateless session; session won't be used to  
            // store user's state.  
            .exceptionHandling()  
            .authenticationEntryPoint(jwtAuthenticationEntryPoint)  
            .and()  
            .sessionManagement()  
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);  
  
    // Add a filter to validate the tokens with every request  
    httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);  
}  
=================================================================================================================  
  
- 다르게 구현한 corsConfigurationSource 설정  
=================================================================================================================  
@Bean  
CorsConfigurationSource corsConfigurationSource() {  
	CorsConfiguration configuration = new CorsConfiguration();  
	configuration.setAllowedOrigins(Arrays.asList("https://example.com"));  
	configuration.setAllowedMethods(Arrays.asList("GET","POST"));  
    // you can configure many allowed CORS headers  
  
	UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();  
	source.registerCorsConfiguration("/**", configuration);  
	return source;  
}  
=================================================================================================================  
  
※ Spring MVC 와 Security 을 둘 다 사용한다면  
	만약 Spring MVC의 CORS 지원을 사용한다면,  
	Spring Security의 CorsConfigurationSource 설정을 생략(omit)할 수 있다.  
	Spring Security는 Spring MVC에서 제공되어지는 CORS 설정을 자동으로 탐지하여 활용(leverage)할 것이다.  
	출처 : https://letsmakemyselfprogrammer.tistory.com/89  

Nginx 설정

https://stackoverflow.com/questions/14501047/how-to-add-a-response-header-on-nginx-when-using-proxy-pass/55692346##55692346  
https://jay-ji.tistory.com/72  
  
proxy_hide_header 를 사용해야 하위 서버의 헤더 옵션에 Niginx 헤더 옵션을 적용할 수 있는 권한을 가져올 수 있다  
proxy_hide_header를 사용하지 않은 value는 스택된다  
"proxy_hide_header Access-Control-Allow-Origin;" 이 옵션을 꼭 같이 줘야함  
=================================================================================================================  
	location / {  
		## 1. hide the Access-Control-Allow-Origin from the server response  
		proxy_hide_header Access-Control-Allow-Origin;  
		## 2. add a new custom header that allows all * origins instead  
		add_header Access-Control-Allow-Origin *;  
  
	}  
=================================================================================================================  
  
https://enable-cors.org/server_nginx.html  
  
=================================================================================================================  
##  
## Wide-open CORS config for nginx  
##  
location / {  
	 if ($request_method = 'OPTIONS') {  
		add_header 'Access-Control-Allow-Origin' '*';  
		add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';  
		##  
		## Custom headers and headers various browsers *should* be OK with but aren't  
		##  
		add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';  
		##  
		## Tell client that this pre-flight info is valid for 20 days  
		##  
		add_header 'Access-Control-Max-Age' 1728000;  
		add_header 'Content-Type' 'text/plain; charset=utf-8';  
		add_header 'Content-Length' 0;  
		return 204;  
	 }  
	 if ($request_method = 'POST') {  
		add_header 'Access-Control-Allow-Origin' '*' always;  
		add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;  
		add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;  
		add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;  
	 }  
	 if ($request_method = 'GET') {  
		add_header 'Access-Control-Allow-Origin' '*' always;  
		add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;  
		add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;  
		add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;  
	 }  
}  
  
=================================================================================================================