-
[20] Spring Web MVC : CORSSpring/Spring boot 2020. 7. 4. 08:26반응형
[CORS]
Single-Origin Policy 1에 의해 하나의 origin 2에서 다른 origin의 resource에 대해 request 할 수 없습니다. 즉, http://localhost:8080에서 사용되고 있는 Rest API를 http://localhost:18080와 같이 다른 origin에서 AJAX 호출 등을 통해 request 할 수 없게 됩니다.
Cross-Origin Resource Sharing (CORS)은 Single-Origin Policy를 우회하기 위해 web browser가 지원하는 기술입니다. CORS를 통해 서로 다른 origin 간에 resource를 sharing 할 수 있도록 해줍니다.
[CORS 사용의 예]
Spring에서 CORS 기능을 사용하기 위해 해야 하는 여러 가지 bean 설정을 Spring boot가 모두 진행합니다. 사용자는 CORS 기능을 사용하기 위해 @CrossOrigin annotation을 붙이기만 하면 됩니다.
CORS를 사용하는 예를 들기 위해 우선 server역할을 할 project(이하 Server Project)와 SOP를 우회하여 resource를 요청할 client역할의 project(이하 Client Project)를 생성합니다.
Step 1
Server Project는 간단한 RestAPI를 제공하도록 작성합니다.
@SpringBootApplication @RestController public class SpringCrossServerApplication { @GetMapping("/hello") public String hello() { return "Hello"; } public static void main(String[] args) { SpringApplication app = new SpringApplication(SpringCrossServerApplication.class); app.run(args); } }
Step2
Client Project는 application.properties file에 다음 property를 추가하여 18080 port에서 실행되도록 합니다. 이로써 Server Project와 Client Project는 다른 origin이 됩니다.
server.port=18080
/src/resources/static/index.html file을 생성하여 Server Project의 Rest API를 비동기 호출하도록 code를 작성합니다. 이 code를 통해 cross origin하게 Server Project의 resource에 대해 성공적으로 response가 돌아오면 alert 창으로 message를 출력하고 실패하면 fail을 출력하도록 하겠습니다.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> CORS Client </body> <script src="/webjars/jquery/3.5.1/dist/jquery.min.js"></script> <script> $(function() { $.ajax("http://localhost:8080/hello") .done(function(msg) { alert(msg); }) .fail(function() { alert("fail"); }); }) </script> </html>
이 code에는 jQuery를 통해 비동기 호출을 하고 있으므로 관련된 의존성을 추가해줘야 정상적으로 동작합니다. Client Project의 pom.xml을 열으 <dependencies></dependencies> tag 안에 jQeury 의존성 관리를 위한 code를 추가합니다.
<dependencies> ... <!-- https://mvnrepository.com/artifact/org.webjars.bower/jquery --> <dependency> <groupId>org.webjars.bower</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency> ... </dependencies>
Step 3
browser 주소창에 http://localhost:18080/을 입력하여 Client Project의 index.html을 reqeust 합니다.
이 reqeust는 Single-Origin Policy에 위배되며 아직 CORS를 사용하고 있지 않기 때문에 alert 창으로 fail이라는 message를 보게 됩니다.
개발자 도구의 console 창을 통해 확인해보면 서로 다른 origin으로 request 할 때 CORS policy에 의해 blocking 하고 있는 것을 볼 수 있습니다. CORS를 사용하여 다른 origin에 reqeust 하기 위해서는 (Server Project의) resource에 'Access-Control-Allow-Origin' header가 추가되어야 한다고 합니다.
Step4
'Access-Control-Allow-Origin' header를 추가하기 위해서는 Server Project의 Rest API에 @CrossOrigin annotation을 붙여줍니다. 변경된 code는 다음과 같습니다.
@SpringBootApplication @RestController public class SpringCrossServerApplication { @CrossOrigin(origins = "http://localhost:18080") //'Access-Control-Allow-Origin' header 추가 @GetMapping("/hello") public String hello() { return "Hello"; } public static void main(String[] args) { SpringApplication app = new SpringApplication(SpringCrossServerApplication.class); app.run(args); } }
이제 다시 browser에서 http://localhost:18080/ 으로 reqeust를 던지면 기대했던 message를 alert창으로 출력하는 것을 확인할 수 있습니다.
tip
test 중 web application이 종료되지 않은 상태에서 다시 build 후 실행하도록 하면 정상적으로 실행이 불가합니다. 이는 기존 실행되던 web application을 종료하여 해결할 수 있습니다.
특정 port에서 실행 중이던 web application이 종료되지 않았을 때는 다음 순서에 따라 종료합니다.
1. terminal을 열고 명령줄에 ps ax | grep tomcat 을 입력하여 process id를 확인합니다.
2. 명령줄에 kill -9 [process id] 를 입력하여 web application을 종료합니다.
[CORS를 광범위로 적용하는 방법]
1. controller 내부의 모든 resource에 대해 CORS 적용해야 할 경우.
controller class에 @CrossOrigin을 붙여줍니다.
@SpringBootApplication @CrossOrigin(origins = "http://localhost:18080") //'Access-Control-Allow-Origin' header 추가 @RestController public class SpringCrossServerApplication { @GetMapping("/hello") public String hello() { return "Hello"; } public static void main(String[] args) { SpringApplication app = new SpringApplication(SpringCrossServerApplication.class); app.run(args); } }
2. 여러 controller에 대해 CORS를 적용해야 할 경우
WebMvcConfigurer interface를 구현하는 web configuration file을 만들어 여러 controller에 대해 CORS를 적용할 수 있습니다. WebMvcConfigurer의 method를 구현하면 Spring MVC에서 제공하는 기능을 그대로 사용하면서 사용자가 추가로 기능을 확장할 수 있게 됩니다. CORS의 전체 적용을 위해 WebMvcConfigurer.addCorsMappings() method를 구현합니다.
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { //전체 resource를 허용할 경우 registry.addMapping("/**")... registry.addMapping("/hello") //mapping할 resource를 지정합니다. .allowedOrigins("http://localhost:18080"); //CORS를 허용할 origin을 지정합니다. } }
이제 @CrossOrigin annotation을 사용하지 않아도 web configuration file에서 설정한 대로 지정된 resource를 특정 origin에 대해 허용합니다.
'Spring > Spring boot' 카테고리의 다른 글
[22] Spring Data : MySQL 설정하기 (0) 2020.07.09 [21] Spring Data : In-memory Database (0) 2020.07.07 [19] Spring Web MVC : Spring HATEOAS (0) 2020.06.30 [18] Spring Web MVC : ExceptionHandler (0) 2020.06.28 [17] Spring Web MVC : HtmlUnit (0) 2020.06.26