스프링부트가 제공하는 SOP와 CORS에 대해 알아보자.

SOP

Single-Origin Policy(SOP) 에서는 같은 origin 에만 요청을 보낼 수 있다.

스프링부트는 기본적으로 SOP가 적용되어 있다. 즉, 기본적으로는 origin이 다른 경우 리소스를 요청할 수 없다.

origin

  • URI 스키마 (http, https)
  • hostname (whiteship.me, localhost)
  • 포트 (8080, 18080)

위의 세가지를 조합한 결과가 하나의 origin이다. 예를 들어 http://localhost:8080에서 REST API를 제공하는 서버가 있고, http://localhost:18080 에서 사용하는 어떠한 애플리케이션에서 해당 REST API 서버에 HTTP 요청을 보내도 SOP를 위반하여 리소스를 응답받을 수 없다.

CORS

Cross-Origin Resource Sharing(CORS)는 서로 다른 origin 끼리 리소스를 공유할 수 있다.

스프링 MVC에서 CrossOrigin를 지원한다. 스프링에서 CORS를 지원하기 위해서 원래는 여러가지 설정을 해야하지만, 스프링부트에서 그러한 설정을 해주기 때문에 @CrossOrigin을 바로 사용할 수 있다.

실습

CORS 실습을 위해 서버와 클라이언트 애플리케이션을 준비하자.

@SpringBootApplication
@RestController
public class WebmvcCorsApplication {

	@GetMapping("hello")
	public String hello() {
		return "hello";
	}

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

}

서버 애플리케이션에는 간단하게 GET /hello에서 hello 문자열을 반환하는 REST 컨트롤러 하나만 작성하여 8080 포트에서 실행한다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<script
        src="https://code.jquery.com/jquery-3.3.1.min.js"
        integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
        crossorigin="anonymous"></script>
<script>
    $(function() {
        $.ajax("http://localhost:8080/hello")
            .done(function(msg) {
                alert(msg);
            })
            .fail(function() {
                alert("fail");
            });
    });
</script>
</body>
</html>

클라이언트 애플리케이션에는 index.html 을 정적리소스 경로에 생성하여 welcome 페이지 지정하며, 18080 포트에서 실행한다. origin이 다른 localhost:8080에 Ajax GET 요청을 전송하여 결과를 출력한다. 지금 상태에서는 fail 콜백이 수행될 것이다.

(index):1 Access to XMLHttpRequest at 'http://localhost:8080/hello' from origin 'http://localhost:18080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

클라이언트는 요청을 전송하기 전에 서버로부터 Access-Control-Allow-Origin를 요청한다. Access-Control-Allow-Origin 헤더에 있는 정보와 클라이언트 자신이 매치가 되면 실제 요청을 보낼 수 있다.

앞서 설명한 것처럼, 스프링부트는 기본적으로 SOP가 적용되어 있기떄문에 다른 origin에게 리소스를 요청할 수 없다. 서버에 CORS 설정을 추가해보자.

@SpringBootApplication
@RestController
public class WebmvcCorsApplication {

	@CrossOrigin(origins = "http://localhost:18080")
	@GetMapping("hello")
	public String hello() {
		return "hello";
	}

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

}

@CrossOrigin을 지정하면서 origins 속성에 CORS를 허용할 origin을 문자열로 지정한다. 여기서는 클라이언트의 origin인 http://localhost:18080을 지정했다.

서버를 다시 시작한 뒤, 클라이언트에서 Ajax 요청을 다시 보내면 이번에는 done 콜백이 실행된다.

@CrossOrigin는 클래스나 @RequestMapping에 지정할 수 있다.

전역 설정

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:18080");
    }
}

WebMvcConfigurer 전역으로 CORS를 설정하여 한 곳에서 관리할 수 있다.

해당 포스팅은 스프링 부트 개념과 활용 강의 내용을 토대로 작성하였습니다.