Spring & Spring Boot

[Spring Boot] CORS 설정 방법 2가지( (+) IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" 에러 해결)

토발자 2024. 4. 1. 16:06
반응형

새로운 프로젝트 진행 중 만나버린 친구..

오랜만이다 CORS 에러.. 안녕?..

 

CORS 에러는 웹 개발자라면 꼭 만날 수 밖에 없는 에러로 명성이 자자하다.

 

구글링 중 본 CORS ERROR 짤이 인상 깊었다..

 


 

CORS란?

Cross-Origin Resource Sharing의 줄임말로 웹 브라우저에서 다른 출처의 리소스 공유에 대한 허용/비허용을 다룬 보안 정책이다.

 

예를 들어, 다른 회사의 API 등 다른 도메인의 API(다른 출처)를 이용하고 싶을 때 CORS 허용 설정이 되어 있어야 성공적으로 API에 접근해 리소스를 공유받을 수 있다.

 

 

 

CORS 설정 방법

CORS 에러를 해결하기 위한 여러 방법이 있겠지만 오늘은 직접 서버에서 HTTP 헤더 설정을 통해 다른 출처를 허용하도록 설정하려고 한다.

 

Spring 서버, Node 서버 등 각 서버에 맞게 HTTP 헤더를 추가해주면 된다.

 

CORS와 연관된 HTTP 헤더 값으로는 다음과 같고, 이 값들을 모두 설정할 필요는 없다,

// 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용한다.
// * 이면 모든 곳에 공개되어 있음을 의미
Access-Control-Allow-Origin : <https://naver.com>

// 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더
Access-Control-Request-Methods : GET, POST, PUT, DELETE

// 요청을 허용하는 헤더
Access-Control-Allow-Headers : Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization

// 클라이언트에서 preflight 의 요청 결과를 저장할 기간 지정
// 60초 동안 preflight 요청을 캐시하는 설정으로, 첫 요청 이후 60초 동안은 OPTIONS 메서드를 사용하는 예비 요청을 보내지 않는다.
Access-Control-Max-Age : 60

// 클라이언트 요청이 쿠키를 통해서 자격 증명을 해야 하는 경우 true
// 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다.
Access-Control-Allow-Credentials : true

// 기본적으로 브라우저에게 노출이 되지 않지만, 브라우저 측에서 접근할 수 있게 허용해주는 헤더 지정
Access-Control-Expose-Headers : Content-Length

 

나는 Spring 서버를 사용하고 있고, 아래 코드도 그에 맞춰 구현했다.

 

방법 1 - CrossOrigin 어노테이션 이용

특정 Controller 혹은 특정 API에만 CORS 설정을 할 수 있는 방법이다.

 

// 특정 controller에만 CORS 적용
@Controller
@CrossOrigin(origins = "*", methods = RequestMethod.GET)
public class testController {

		// 특정 API에만 CORS 적용
		@GetMapping("/result")
		@CrossOrigin(origins = "*", methods = RequestMethod.GET)
		public ResponseEntity<ResultDto> getResultDto(@RequestParam(name = "code", required = false) String code){
		    return ResponseEntity.ok(ResultDto.builder()
		            .idx(1)
		            .subject("CORS 설정 방법")
		            .build());
		}
}

 

방법 2 - WebMvcConfigurer 이용해 Spring 서버 전역적으로 설정

Spring 서버 전역적으로 CORS 설정을 해주기 위해서는 아래와 같이 Configuration 어노테이션을 붙인 스프링 설정 클래스를 생성해준다.

 

// Spring 서버 전역적으로 CORS 설정
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*") // 허용할 출처 : 특정 도메인만 받을 수 있음
                .allowedMethods("GET", "POST") // 허용할 HTTP method
                .allowCredentials(true); // 쿠키 인증 요청 허용
    }
}

registry.addMapping 을 이용해 CORS를 적용할 URL패턴을 정의할 수 있다.

위의 코드처럼 "/**" 와일드 카드를 사용할 수 있다.

 

allowedOrigins 메소드를 이용해서 자원 공유 허락할 Origin 지정할 수 있다.

마찬가지로 "*"로 모든 Origin을 허락할 수 있다.

 

allowedMethods를 이용해서 허용할 HTTP method를 지정할 수 있다.

"*"를 이용해 모든 method를 허용할 수 있다.

 

이렇게 구현하고 실행을 하면.. 에러가 날 것이다.

java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
	at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:473) ~[spring-web-5.3.27.jar:5.3.27]
	at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:532) ~[spring-webmvc-5.3.27.jar:5.3.27]
	...

 

Spring Boot에서 CORS 설정 시 allowedOrigins("*")와 allowCredentials(true)를 동시에 사용할 수 없도록 업데이트 되었기 때문이라고 한다.

 

해결 방법은 아래와 같다.

// Spring 서버 전역적으로 CORS 설정
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*") // “*“같은 와일드카드를 사용
                .allowedMethods("GET", "POST") // 허용할 HTTP method
                .allowCredentials(true); // 쿠키 인증 요청 허용
    }
}
반응형