Cross-Origin Resource Sharing, CORS
λ€λ₯Έ μΆμ²μ μμμ 곡μ ν μ μλλ‘ μ€μ νλ κΆν 체μ
λΈλΌμ°μ μμλ 보μμ μΈ μ΄μ λ‘ cross-origin HTTP μμ²λ€μ μ ννλ€. λ°λΌμ cross-origin μμ²μ νλ €λ©΄ μλ²μ λμκ° νμνλ€. λ§μ½ μλ²κ° λμνλ€λ©΄ λΈλΌμ°μ μμλ μμ²μ νλ½νκ³ , λμνμ§ μλλ€λ©΄ λΈλΌμ°μ μμ κ±°μ νλ€.
κ·Έλμ λΈλΌμ°μ μμ cross-origin μμ²μ μμ νκ² ν μ μλλ‘ νλ λ©μ»€λμ¦μ΄λ€.
λ°λΌμ CORSλ₯Ό μ€μ ν΄μ£Όμ§ μμ κ²½μ°, μνλλλ‘ λ¦¬μμ€λ₯Ό 곡μ νμ§ λͺ»νκ² λλ€.
λ€μ μ€ ν κ°μ§λΌλ λ€λ₯Έ κ²½μ°λ₯Ό λ§νλ€.
- νλ‘ν μ½ - httpμ httpsλ νλ‘ν μ½μ΄ λ€λ₯΄λ€.
- λλ©μΈ - domain.comκ³Ό other-domain.com μ λ€λ₯΄λ€.
- ν¬νΈ λ²νΈ - 8080ν¬νΈμ 3000ν¬νΈλ λ€λ₯΄λ€.
CORSκ° μμ΄ λͺ¨λ κ³³μμ λ°μ΄ν°λ₯Ό μμ²ν μ μκ² λλ©΄, λ€λ₯Έ μ¬μ΄νΈμμ μλ μ¬μ΄νΈλ₯Ό νλ΄λΌ μ μκ² λλ€.
e.g. κΈ°μ‘΄ μ¬μ΄νΈμ μμ ν λμΌνκ² λμνλλ‘ νμ¬ μ¬μ©μκ° λ‘κ·ΈμΈνκ² λ§λ€κ³ , λ‘κ·ΈμΈνλ©΄ μΈμ μ νμ·¨νμ¬ μ μμ μΌλ‘ μ 보λ₯Ό μΆμΆνκ±°λ λ€λ₯Έ μ¬λμ μ 보λ₯Ό μ λ ₯νλ λ± κ³΅κ²©ν μ μλ€.
λ°λΌμ μ΄λ κ² κ³΅κ²©μ ν μ μλλ‘ λΈλΌμ°μ μμ 보νΈνκ³ , νμν κ²½μ°μλ§ μλ²μ νμνμ¬ μμ²ν μ μλλ‘ νκΈ° μν΄ νμνλ€.
Simple requests
μΈ κ²½μ°
- μλ²λ‘ μμ²μ νλ€.
- μλ²μ μλ΅μ΄ μμ λ λΈλΌμ°μ κ° μμ²ν Orgin κ³Ό ν€λ Access-Control-Request-Headers μ κ°μ λΉκ΅νμ¬ μ ν¨ν μμ²μ΄λΌλ©΄ 리μμ€λ₯Ό μλ΅νλ€. λ§μ½ μ ν¨νμ§ μμ μμ²μ΄λΌλ©΄ λΈλΌμ°μ μμ μ΄λ₯Ό λ§κ³ μλ¬κ° λ°μνλ€.
Simple request
λ?
HTTP methodκ° λ€μ μ€ νλμ΄λ©΄μ
- GET
- HEAD
- POST
μλμΌλ‘ μ€μ λλ ν€λλ μ μΈνκ³ , μ€μ ν μ μλ λ€μ ν€λλ€λ§ λ³κ²½νλ©΄μ
- Accept
- Accept-Language
- Content-Language
Content-Type
μ΄ λ€μκ³Ό κ°μ κ²½μ°
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
Simple requestλΌκ³ λΆλ₯Έλ€. μ΄ μμ²μ μΆκ°μ μΌλ‘ νμΈνμ§ μκ³ λ°λ‘ λ³Έ μμ²μ 보λΈλ€.
- Origin ν€λμ
νμ¬ μμ²νλ origin
κ³Ό,Access-Control-Request-Method
ν€λμ μμ²νλ HTTP methodμAccess-Control-Request-Headers
μμ² μ μ¬μ©ν ν€λλ₯ΌOPTIONS
λ©μλλ‘ μλ²λ‘ μμ²νλ€. μ΄λ λ΄μ©λ¬Όμ μμ΄ ν€λλ§ μ μ‘νλ€. - λΈλΌμ°μ κ° μλ²μμ μλ΅ν ν€λλ₯Ό λ³΄κ³ μ ν¨ν μμ²μΈμ§ νμΈνλ€. λ§μ½ μ ν¨νμ§ μμ μμ²μ΄λΌλ©΄ μμ²μ μ€λ¨λκ³ μλ¬κ° λ°μνλ€. λ§μ½ μ ν¨ν μμ²μ΄λΌλ©΄ μλ μμ²μΌλ‘ 보λ΄λ €λ μμ²μ λ€μ μμ²νμ¬ λ¦¬μμ€λ₯Ό μλ΅λ°λλ€.
Simple requestsκ° μλ cross-origin μμ²μ λͺ¨λ preflight μμ²μ νκ² λλλ°, μ€μ μμ²μ 보λ΄λ κ²μ΄ μμ νμ§ νμΈνκΈ° μν΄ λ¨Όμ OPTIONS λ©μλλ₯Ό μ¬μ©νμ¬ cross-origin HTTP μμ²μ 보λΈλ€. μ΄λ κ² νλ μ΄μ λ μ¬μ©μ λ°μ΄ν°μ μν₯μ λ―ΈμΉ μ μλ μμ²μ΄λ―λ‘ μ¬μ μ νμΈ ν λ³Έ μμ²μ 보λΈλ€.
- Origin
- Access-Control-Request-Method
preflight
μμ²μ ν λ μ€μ μμ²μμ μ΄λ€ λ©μλλ₯Ό μ¬μ©ν κ²μΈμ§ μλ²μκ² μ리기 μν΄ μ¬μ©λλ€.
- Access-Control-Request-Headers
preflight
μμ²μ ν λ μ€μ μμ²μμ μ΄λ€ headerλ₯Ό μ¬μ©ν κ²μΈμ§ μλ²μκ² μ리기 μν΄ μ¬μ©λλ€.
- Access-Control-Allow-Origin
- λΈλΌμ°μ κ° ν΄λΉ originμ΄ μμμ μ κ·Όν μ μλλ‘ νμ©νλ€.
- Access-Control-Expose-Headers
- λΈλΌμ°μ κ° μ‘μΈμ€ν μ μλ μλ² νμ΄νΈλ¦¬μ€νΈ ν€λλ₯Ό νμ©νλ€.
- Access-Control-Max-Age
- μΌλ§λ μ€λ«λμΒ
preflight
μμ²μ΄ μΊμ± λ μ μλμ§λ₯Ό λνλΈλ€.
- μΌλ§λ μ€λ«λμΒ
- Access-Control-Allow-Credentials
Credentials
κ° true μΌ λ μμ²μ λν μλ΅μ΄ λ ΈμΆλ μ μλμ§λ₯Ό λνλ λλ€.preflight
μμ²μ λν μλ΅μ μΌλΆλ‘ μ¬μ©λλ κ²½μ° μ€μ μ격 μ¦λͺ μ μ¬μ©νμ¬ μ€μ μμ²μ μνν μ μλμ§λ₯Ό λνλ λλ€.- κ°λ¨ν GET μμ²μΒ
preflight
λμ§ μμΌλ―λ‘ μ격 μ¦λͺ μ΄ μλ 리μμ€λ₯Ό μμ²νλ©΄ ν€λκ° λ¦¬μμ€μ ν¨κ» λ°νλμ§ μμΌλ©΄ λΈλΌμ°μ μμ μλ΅μ 무μνκ³ μΉ μ½ν μΈ λ‘ λ°ννμ§ μμ΅λλ€.
- Access-Control-Allow-Methods
- preflight`μμ²μ λν λν μλ΅μΌλ‘ νμ©λλ λ©μλλ€μ λνλ λλ€.
- Access-Control-Allow-Headers
preflight
μμ²μ λν λν μλ΅μΌλ‘ μ€μ μμ² μ μ¬μ©ν μ μλ HTTP ν€λλ₯Ό λνλ λλ€.
Globalνκ² μ μ©νλ λ°©λ²μΌλ‘, config ν¨ν€μ§λ₯Ό λ§λ€μ΄μ€λ€.
κ²½λ‘λ /src/main/java/{project}/config λ§λ€μ΄μ§ config ν¨ν€μ§ μμ WebConfig ν΄λμ€λ₯Ό λ§λ€μ΄μ€λ€.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
registry.addMapping
μ μ΄μ©ν΄μ CORS μ μ©ν URL ν¨ν΄
μ μ μν μ μλ€.
μ μ²λΌ β/**β μμΌλ μΉ΄λλ₯Ό μ¬μ©ν μλ μλ€.
λν Ant-styleλ μ§μνλ©° β/somePath/**β μ΄λ κ² μ μ©ν μλ μλ€.
Default κ°μ μλμ κ°λ€.
- Allow all origins.
- Allow βsimpleβ methods GET, HEAD and POST
- Allow all headers
- Set max age to 1800 seconds (30 minutes).
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*");
}
}
.allowedOrigins("http://localhost:8080", "http://localhost:8081"); // ν λ²μ μ¬λ¬ Methodλ₯Ό νμ©
allowedOrigins λ©μλλ₯Ό μ΄μ©ν΄μ μμ 곡μ λ₯Ό νλ½ν Originμ μ§μ ν μ μλ€.
β*βλ‘ λͺ¨λ Originμ νλ½ν μ μλ€.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST");
}
}
allowedMethodsλ₯Ό μ΄μ©ν΄μ νμ©ν HTTP methodλ₯Ό μ§μ
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST")
.maxAge(3000);
}
}
maxAge λ©μλλ₯Ό μ΄μ©ν΄μ μνλ μκ°λ§νΌ pre-flight 리νμ€νΈλ₯Ό μΊμ± ν΄λ μ μλ€.
Controller λλ λ©μλλ¨μμ annotationμ ν΅ν΄ μ μ©νλ λ°©λ²
@RequestMapping("/somePath")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class SomeController {
}
@RestController
@RequestMapping("/somePath")
public class SomeController {
@CrossOrigin(origins="*")
@RequestMapping(value = "/{something}",method = RequestMethod.DELETE)
public ResponseEntity<String> delete(@PathVariable Long reservationNo) throws Exception{
}
}
- CorssOrigin μ΄λ Έν μ΄μ μ μ¬μ©νλ©΄ globalνκ² μ€μ νλ κ² κ³Ό κ°μ΄ νμ©ν originsμ΄λ methodsλ₯Ό μ§μ ν μ μλ€.
- origins, methods, maxAge, allowedHeadersλ₯Ό μ¬μ©ν μ μλ€.
[ref]
https://hannut91.github.io/blogs/infra/cors
https://dev-pengun.tistory.com/entry/Spring-Boot-CORS-μ€μ νκΈ°