Java/Spring Boot
[Java] Spring Boot 환경에서 CORS(Cross Origin Resource Sharing) 이해하고 활용하기 -1
adjh54
2024. 10. 26. 16:20
반응형
해당 글에서는 Spring Boot 환경에서 CORS를 이해하고 활용하는 방법에 대해 알아봅니다.
1) 교차 출처 리소스 공유 : CORS(Cross Origin Resource Sharing)
💡교차 출처 리소스 공유 (CORS: Cross-Origin Resource Sharing)
- 브라우저가 자신의 출처가 아닌 다른 어떤 출처로부터 자원을 요청하는 것에 대해 허용하도록 서버가 이를 허가해 주는 HTTP 헤더 기반 메커니즘을 의미합니다.
- 서버가 실제 요청을 허가할 것인지 확인하기 위해 브라우저가 보내는 ‘사전 요청(프리플라이트, Preflight)’ 메커니즘에 의존합니다.
- 이 사전 요청을 통해 브라우저는 실제 요청에서 사용할 HTTP 메서드와 헤더에 대한 정보가 표시된 헤더에 담아 보냅니다.
- Spring Boot를 이용하는 경우 이에 대한 설정을 spring-boot-starter-web 의존성에 기본이 되어 사용됩니다.
[더 알아보기]
💡 출처(Origin)
- 웹 페이지나 리소스의 출처를 나타냅니다. 일반적으로 프로토콜(http/https), 도메인, 포트 조합으로 구성이 됩니다.
- 예를 들어서 https://example.com:443를 의미합니다. https 프로토콜을 이용하며 example.com의 도메인을 가지며, 기본 포트인 443 포트를 가집니다.
1. 동일한 출처(Same Origin)와 다른 출처(Cross Origin)
💡동일한 출처(Same Origin)와 다른 출처(Cross Origin)
💡동일한 출처(Same Origin)
- domain-a.com이라는 웹 브라우저와 domain-a.com이라는 웹 서버는 동일한 출처(Origin)를 가지고 있습니다.
1. 웹 브라우저에서는 [GET] /index.html 페이지를 웹 서버로 요청을 합니다.
- 해당 페이지에는 styles.css, header.png 파일이 포함되어 있어 함께 요청이 됩니다.
2. 웹 서버에서는 동일한 출처(Same-origin) 임을 판단하여 리소스 접근에 대한 요청을 수락(allow)하여 페이지와 이미지를 제공합니다.
💡 다른 출처(Cross Origin)
- domain-b.com이라는 웹 브라우저와 domain-a.com이라는 웹 서버는 서로 다른 출처(Origin)를 가지고 있습니다.
1. 웹 브라우저에서는 [GET] img.png 파일을 웹 서버에 요청합니다.
- 웹 브라우저에서는 동일한 출처(Same-Origin)가 아님이 판단되어서 CORS 오류를 웹 브라우저에게 반환합니다.
2. 해당 상황에서 CORS를 허용하였다면 서로 다른 출처(Origin)에서도 제공을 해줄 수 있습니다.
2. SOP(Same-Origin Policy) 정책 : 교차 출처 리소스 고유 정책
💡SOP(Same-Origin Policy) 정책
- 웹 보안의 중요한 개념으로 동일 출처 정책을 의미합니다. 이는 웹 브라우저가 다른 출처의 리소스에 접근하는 것을 제한하는 보안 메커니즘을 의미합니다.
- 이는 웹 애플리케이션의 보안을 강화하지만 때로는 합법적인 크로스 요청을 방해할 수 있어 CORS가 필요하게 됩니다.
2.1. SOP(Same-Orgin Policy) 정책 특징
💡SOP(Same-Orgin Policy) 정책 특징
특징 | 설명 |
동일 출처 요구 | 웹 페이지와 그 페이지가 요청하는 리소스의 출처가 같아야 합니다. |
출처의 정의 | 프로토콜(http/https), 도메인, 포트가 모두 동일해야 동일 출처로 간주됩니다. |
보안 강화 | 악의적인 스크립트가 다른 웹사이트의 데이터에 무단으로 접근하는 것을 방지합니다. |
제한 완화 | CORS(Cross-Origin Resource Sharing)를 통해 필요한 경우 이 정책을 완화할 수 있습니다. |
2.2. 동일한 출처와 서로 다른 출처 비교
💡동일한 출처와 서로 다른 출처 비교
- 기준이 되는 “http://example.com”일 경우 동일한 출처로 간주되는 경우와 서로 다른 출처로 간주되는 경우에 대해 알아봅니다.
# 기준 도메인
<http://example.com>
# 동일한 출처로 간주되는 경우
<https://example.com:443/page1>
<https://example.com:443/page2>
# 서로 다른 출처로 간주되는 경우
<https://example.com> # 프로토콜(HTTP, HTTPS)이 다른 경우
<https://example.com:8080> # 포트 번호가 다른 경우(기본 443 vs 8080)
<https://sub.example.com> # 호스트(도메인)이 다른 경우
3. CORS 사용 목적
목적 | 설명 |
보안 강화 | 악의적인 웹사이트로부터 사용자 데이터를 보호합니다. |
리소스 공유 허용 | 필요한 경우 다른 출처의 리소스에 접근할 수 있도록 합니다. |
API 접근 제어 | 서버가 허용한 클라이언트만 API에 접근할 수 있도록 합니다. |
마이크로서비스 아키텍처 지원 | 서로 다른 도메인에서 실행되는 서비스 간 통신을 가능하게 합니다. |
개발 환경 지원 | 로컬 개발 환경과 실제 서버 간의 통신을 허용합니다. |
💡 [참고] CORS에 대해 궁금하시면 아래의 글을 참고하시면 더욱 이해할 수 있습니다.
반응형
2) Spring Boot 환경에서 CORS 활용 방법
💡Spring Boot 환경에서 CORS 구현 방법
- 이를 통해서 브라우저에서 서버로 요청에 대해 제한을 두고 지정한 출처(Origin)에 대해서만 허용할 수 있도록 합니다.
1. 라이브러리 추가
dependencies {
// [Spring Boot Starter]
implementation "org.springframework.boot:spring-boot-starter-web" // Spring Boot Web
}
2. 설정 클래스 구성 : API 서버 전역 적용
💡설정 클래스 구성 : API 서버 전역 적용
- Spring MVC의 Java-based configuration을 사용자 정의할 수 있게 해주는 인터페이스입니다.
- 이 인터페이스를 구현함으로써 Spring MVC의 다양한 구성 요소를 커스터마이징 할 수 있습니다.
- CORS를 위해서는 addCorsMappings를 활용합니다.
💡 [참고] WebMvcConfigurer 클래스 API Document
메서드 | 리턴 값 | 설명 |
addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) | default void | 사용자 정의 컨트롤러 메서드 인자 타입을 지원하기 위한 리졸버 추가 |
addCorsMappings(CorsRegistry registry) | default void | "전역" 교차 출처 요청 처리 구성 |
addFormatters(FormatterRegistry registry) | default void | 기본 등록된 것 외에 추가적인 Converter와 Formatter 추가 |
addInterceptors(InterceptorRegistry registry) | default void | 컨트롤러 메서드 호출 및 리소스 핸들러 요청의 전처리 및 후처리를 위한 Spring MVC 수명주기 인터셉터 추가 |
addResourceHandlers(ResourceHandlerRegistry registry) | default void | 웹 애플리케이션 루트, 클래스패스 및 기타 위치에서 이미지, js, css 파일과 같은 정적 리소스를 제공하기 위한 핸들러 추가 |
addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) | default void | 사용자 정의 컨트롤러 메서드 반환 값 타입을 지원하기 위한 핸들러 추가 |
addViewControllers(ViewControllerRegistry registry) | default void | 응답 상태 코드 및/또는 응답 본문을 렌더링할 뷰로 미리 구성된 간단한 자동화된 컨트롤러 구성 |
configureAsyncSupport(AsyncSupportConfigurer configurer) | default void | 비동기 요청 처리 옵션 구성 |
configureContentNegotiation(ContentNegotiationConfigurer configurer) | default void | 콘텐츠 협상 옵션 구성 |
configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) | default void | 처리되지 않은 요청을 서블릿 컨테이너의 "기본" 서블릿으로 전달하는 핸들러 구성 |
configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) | default void | 예외 리졸버 구성 |
configureMessageConverters(List<HttpMessageConverter<?>> converters) | default void | 요청 본문에서 읽고 응답 본문에 쓰기 위한 HttpMessageConverter 구성 |
configurePathMatch(PathMatchConfigurer configurer) | default void | HandlerMapping 경로 일치 옵션 구성 지원 (예: 파싱된 PathPatterns 또는 PathMatcher를 사용한 문자열 패턴 일치 사용 여부, 후행 슬래시 일치 여부 등) |
configureViewResolvers(ViewResolverRegistry registry) | default void | 컨트롤러에서 반환된 문자열 기반 뷰 이름을 구체적인 View 구현으로 변환하기 위한 뷰 리졸버 구성 |
extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) | default void | 기본적으로 구성된 예외 리졸버 목록 확장 또는 수정 |
extendMessageConverters(List<HttpMessageConverter<?>> converters) | default void | 구성되거나 기본 목록으로 초기화된 후 변환기 목록 확장 또는 수정 |
getMessageCodesResolver() | default MessageCodesResolver | 데이터 바인딩 및 유효성 검사 오류 코드에서 메시지 코드를 생성하기 위한 사용자 정의 MessageCodesResolver 제공 |
getValidator() | default Validator | 기본적으로 생성된 것 대신 사용자 정의 Validator 제공 |
2.1. API 서버 전역 : 모두 허용
💡API 서버 전역 : 모두 허용
- 해당 경우는 Spring Boot 애플리케이션에서 CORS(Cross-Origin Resource Sharing) 설정을 구성하는 방법입니다.
- 해당 경우는 CORS 접근 시 이에 대한 허용 사항에 대해서 정의하였습니다.
- WebMvcConfigurer 클래스의 구현체를 구성하였습니다. 그중에서 addCorsMappings 메서드에 대해서 오버라이딩하여 재구성합니다.
💡 모든 CORS에 대해서 허용하는 경우 예시
- 해당 API로 접근하는 모든 브라우저에 대해 허용하는 경우의 예시입니다.
- 이 경우에는 보안상에 문제가 있기에 사용을 권하지 않지만 개발 테스트를 위해서 제한적으로 사용하는 것이 좋습니다.
메서드 | 설명 |
addMapping("/**") | 모든 경로에 대해 CORS 설정을 적용합니다. |
allowedOrigins("*") | 모든 오리진(출처)에서의 요청을 허용합니다. |
allowedMethods("*") | 허용되는 HTTP 메서드를 지정합니다. |
allowedHeaders("*") | 모든 헤더를 허용합니다. |
allowCredentials(true) | 인증된 요청을 허용합니다 (예: 쿠키, HTTP 인증). |
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true);
}
}
2.2. API 서버 전역 : 특정 제약적 허용
💡API 서버 전역 : 특정 제약적 허용
- 해당 경우는 Spring Boot 애플리케이션에서 CORS(Cross-Origin Resource Sharing) 설정을 구성하는 방법입니다. 이는 CORS 접근 시 이에 대한 허용 사항에 대해서 정의하였습니다.
- WebMvcConfigurer 클래스의 구현체를 구성하였습니다. 그중에서 addCorsMappings 메서드에 대해서 오버라이딩하여 재구성합니다.
💡특정 제약적 CORS 허용하는 경우 예시
- 해당 API로 접근하는 특정 브라우저에 대해서만 허용하는 예시입니다.
- 해당 경우에서는 JWT 인증방식을 통해서 Authorization 헤더를 통해 AccessToken을 주고받으며 x-refresh-token 헤더를 통해 RefreshToken을 주고받는 예시를 보여주고 있습니다.
메서드 | 설명 |
addMapping("/api/**") | CORS 설정을 적용할 API 경로를 지정합니다. |
allowedOrigins("http://localhost:3000") | 허용할 출처(origin)를 설정합니다. 여기서는 localhost:3000만 허용합니다. |
allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") | 허용할 HTTP 메서드를 지정합니다. |
allowedHeaders("Authorization", “x-refresh-token”, "Content-Type") | 허용할 HTTP 헤더를 지정합니다. |
exposedHeaders("Authorization", "x-refresh-token") | 브라우저에 노출할 응답 헤더를 지정합니다. |
allowCredentials(true) | 인증된 요청(예: 쿠키, HTTP 인증)을 허용합니다. |
maxAge(3600) | 프리플라이트 요청 결과를 캐시할 시간(초)을 설정합니다. |
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("<http://localhost:3000>")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("Authorization", "x-refresh-token", "Content-Type")
.exposedHeaders("Authorization", "x-refresh-token")
.allowCredentials(true)
.maxAge(3600);
}
}
💡[참고] CorsRegistration 클래스 API Document
메서드 | 반환 타입 | 설명 |
allowCredentials(boolean allowCredentials) | CorsRegistration | 브라우저가 주석이 달린 엔드포인트로 크로스 도메인 요청과 함께 자격 증명(예: 쿠키)을 보내야 하는지 여부를 설정합니다. |
allowedHeaders(String... headers) | CorsRegistration | 실제 요청 중에 사용할 수 있도록 사전 요청이 나열할 수 있는 헤더 목록을 설정합니다. |
allowedMethods(String... methods) | CorsRegistration | 허용할 HTTP 메서드를 설정합니다. |
allowedOriginPatterns(String... patterns) | CorsRegistration | 브라우저에서 크로스 오리진 요청이 허용되는 오리진을 지정하기 위한 더 유연한 패턴을 지원하는allowedOrigins(String...)의 대안입니다. |
allowedOrigins(String... origins) | CorsRegistration | 브라우저에서 크로스 오리진 요청이 허용되는 오리진을 설정합니다. |
allowPrivateNetwork(boolean allowPrivateNetwork) | CorsRegistration | 사설 네트워크 액세스가 지원되는지 여부를 설정합니다. |
combine(CorsConfiguration other) | CorsRegistration | 주어진CorsConfiguration을 현재 구성 중인 것에 적용합니다. 이는CorsConfiguration.combine(CorsConfiguration)을 통해 이루어지며, 이는CorsConfiguration.applyPermitDefaultValues()로 초기화되었습니다. |
exposedHeaders(String... headers) | CorsRegistration | 실제 응답이 가질 수 있고 노출될 수 있는 응답 헤더 목록을 설정합니다. |
getCorsConfiguration() | protected CorsConfiguration | CORS 구성을 가져옵니다. |
getPathPattern() | protected String | 경로 패턴을 가져옵니다. |
maxAge(long maxAge) | CorsRegistration | 사전 요청에 대한 응답을 클라이언트가 캐시할 수 있는 시간(초)을 구성합니다. |
3. Controller 클래스에 적용하는 방법
💡Controller 클래스에 적용하는 방법
- 해당 경우는 @CrossOrigin 어노테이션을 통해서, Controller 전체에 CORS 접근 가능여부를 적용할 수 있습니다.
💡 특정 Controller 클래스에 사용 예시
- 아래와 같이 @CrossOrigin 어노테이션을 통해서 http://localhost:3001 출처(origin)에 대해서만 접근을 허용했습니다.
package com.adjh.springbootcors.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* Please explain the class!!
*
* @author : jonghoon
* @fileName : UserController
* @since : 10/26/24
*/
@Slf4j
@Controller
@RequestMapping("api/v1/user")
@CrossOrigin(origins = "<http://localhost:3001>",
methods = {RequestMethod.GET, RequestMethod.POST},
maxAge = 3600,
allowedHeaders = "*")
public class UserController {
/**
* [API] 사용자 리스트 조회
*
* @return ResponseEntity
*/
@PostMapping("/user")
public ResponseEntity<Object> selectUser() {
List<Object> resultList = new ArrayList<>();
return new ResponseEntity<>(resultList, HttpStatus.OK);
}
/**
* [API] 사용자 리스트 조회
*
* @return ResponseEntity
*/
@PostMapping("/login")
public ResponseEntity<Object> login() {
Object resultObj = new Object();
return new ResponseEntity<>(resultObj, HttpStatus.OK);
}
}
💡아래와 같은 403 오류가 발생하였습니다.
- 호출되는 브라우저는 3000 포트이기에 허용되는 포트가 아니어서 아래와 같은 오류가 발생하였습니다.
- Access to XMLHttpRequest at 'http://localhost:8080/api/v1/user/user' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
💡 @CrossOrigin(origins = "http://localhost:3000")로 수정한 경우 아래와 같이 정상적으로 리소스를 반환받았습니다.
💡 [참고] CrossOrign API Doucment
속성 | 속성 타입 | 설명 |
allowCredentials | String | 브라우저가 주석이 달린 엔드포인트로 크로스 도메인 요청과 함께 자격 증명(예: 쿠키)을 보내야 하는지 여부를 설정합니다. |
allowedHeaders | String[] | 실제 요청에서 허용되는 요청 헤더 목록입니다. 모든 헤더를 허용하려면"*"를 사용할 수 있습니다. |
allowPrivateNetwork | String | 사설 네트워크 액세스가 지원되는지 여부를 설정합니다. |
exposedHeaders | String[] | 사용자 에이전트가 클라이언트에서 접근할 수 있도록 허용하는 응답 헤더 목록입니다. 모든 헤더를 노출하려면"*"를 사용할 수 있습니다. |
maxAge | long | 사전 요청 응답에 대한 캐시 지속 시간의 최대 연령(초)을 설정합니다. |
methods | RequestMethod[] | 지원되는 HTTP 요청 메서드 목록을 설정합니다. |
originPatterns | String[] | origins()의 대안으로, 더 유연한 오리진 패턴을 지원합니다. |
origins | String[] | 크로스 오리진 요청이 허용되는 오리진 목록을 설정합니다. |
value | String[] | origins()의 별칭입니다. |
4. 특정 Controller 메서드의 엔드포인트에 적용하는 방법
💡특정 Controller 엔드포인트에 적용하는 방법
- @CrossOrigin 어노테이션을 통해서, Controller의 메서드 별로 CORS 접근 가능여부를 적용할 수 있습니다.
💡특정 Controller 엔드포인트에 적용하는 사용 예시
- Controller 클래스 내에 메서드에 각각 @CrossOrigin을 통해서 접근 허용/제한을 두었습니다.
- [POST] /api/v1/user/user로 접근하는 경우는 출처(origin)를 http://localhost:3000로만 두었습니다.
- [POST] /api/v1/user/login으로 접근하는 경우는 출처(origin)를 http://localhost:3001로만 두었습니다.
- 서로 호출 자체에 Origin이 포트로 다른 형태입니다.
package com.adjh.springbootcors.controller;
@Slf4j
@Controller
@RequestMapping("api/v1/user")
public class UserController {
/**
* [API] 사용자 리스트 조회
*
* @return ResponseEntity
*/
@CrossOrigin(origins = "<http://localhost:3000>", allowedHeaders = "*")
@PostMapping("/user")
public ResponseEntity<Object> selectUser() {
List<Object> resultList = new ArrayList<>();
return new ResponseEntity<>(resultList, HttpStatus.OK);
}
/**
* [API] 사용자 리스트 조회
*
* @return ResponseEntity
*/
@CrossOrigin(origins = "<http://localhost:3001>", allowedHeaders = "*")
@PostMapping("/login")
public ResponseEntity<Object> login() {
Object resultObj = new Object();
return new ResponseEntity<>(resultObj, HttpStatus.OK);
}
}
💡 아래와 같이 ‘허용 리소스’를 선택하여 수행하였습니다.
- http://localhost:3000 내에서 호출되었기에 해당 Endpoint의 경우 이에 대해 허용이 되었기에 리소스 응답 값을 반환받았습니다.
💡아래와 같이 ‘허용 리소스’를 선택하여 수행하였습니다.
- http://localhost:3000 내에서 호출되었기에 해당 Endpoint의 경우 허용이 되어 있지 않기에 리소스 응답 값을 반환받지 못하였습니다.
5. Spring Boot Security 내에서 CORS 적용 방법 : CorsConfigurationSource
💡 Spring Boot Security 내에서 CORS 적용 방법 : CorsConfigurationSource
- 아래와 같이 Spring Security를 적용하는 과정에서 CorsConfigurationSource 클래스를 활용하여 WebSecurityConfig를 구성할 수 있습니다.
💡예시 코드
- Spring Boot Security를 구성할 때 SecurityFilterChain를 통해서 이를 구현했습니다.
- 해당 http에 대해 .cors()에 대한 커스텀한 설정을 적용하였습니다.
메서드 | 설명 | 적용 사항 설명 |
setAllowedOrigins | 허용할 출처(origin)를 설정합니다. | http://localhost:3000에서의 요청만 허용 |
setAllowedMethods | 허용할 HTTP 메서드를 설정합니다. | 모든 HTTP 메서드를 허용 |
setAllowedHeaders | 허용할 HTTP 헤더를 설정합니다. | 모든 헤더를 허용 |
setAllowCredentials | 인증 정보 포함 여부를 설정합니다. | 인증 정보(쿠키, HTTP 인증)를 포함할 수 있도록 함 |
setMaxAge | 프리플라이트 요청 결과의 캐시 시간을 설정합니다. | 프리플라이트 요청 결과를 3600초(1시간) 동안 캐시 |
UrlBasedCorsConfigurationSource | URL 패턴별 CORS 설정을 관리하는 클래스입니다. | URL 패턴별로 CORS 설정을 적용할 수 있게 해주는 클래스 |
registerCorsConfiguration | 특정 URL 패턴에 CORS 설정을 등록합니다. | 모든 경로("/**")에 대해 이 CORS 설정을 적용 |
@Slf4j
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
/**
* 2. HTTP에 대해서 ‘인증’과 ‘인가’를 담당하는 메서드이며 필터를 통해 인증 방식과 인증 절차에 대해서 등록하며 설정을 담당하는 메서드입니다.
*
* @param http HttpSecurity
* @return SecurityFilterChain
* @throws Exception Exception
*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable) // CSRF 보호 비활성화
.cors(cors -> cors.configurationSource(corsConfigurationSource())) // CORS 커스텀 설정 적용
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) // 우선 모든 요청에 대한 허용
.addFilterBefore(jwtAuthorizationFilter(), BasicAuthenticationFilter.class) // JWT 인증 (커스텀 필터)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션 미사용 (JWT 사용)
.addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 사용자 인증(커스텀 필터)
.formLogin(AbstractHttpConfigurer::disable) // 폼 로그인 비활성화
.build();
}
/**
* 10. CORS에 대한 설정을 커스텀으로 구성합니다.
*
* @return CorsConfigurationSource
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("<http://localhost:3000>")); // 허용할 오리진
configuration.setAllowedMethods(List.of("*")); // 허용할 HTTP 메서드
configuration.setAllowedHeaders(List.of("*")); // 모든 헤더 허용
configuration.setAllowCredentials(true); // 인증 정보 허용
configuration.setMaxAge(3600L); // 프리플라이트 요청 결과를 3600초 동안 캐시
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration); // 모든 경로에 대해 이 설정 적용
return source;
}
}
💡 [참고] CorsConfigurationSource 클래스 API Document
오늘도 감사합니다. 😀
반응형