대부분의 API가 하나의 동일한 CORS 정책을 공유하는, 일반적인 프로젝트 초기에 가장 적합한 방식입니다.
http://localhost:3000이나 https://app.moyeohaeng.com과 같은 단일 종류의 클라이언트로부터 요청을 받습니다.Customizer.withDefaults())SecurityConfig는 CORS 설정의 구체적인 내용을 모르고, 스프링 컨테이너에 등록된 CorsConfigurationSource 빈을 자동으로 가져와 사용합니다. 이를 통해 설정을 분리하고 코드를 간결하게 유지할 수 있습니다.
application.yml - 설정 외부화CORS 정책을 외부 설정 파일로 분리하여 관리합니다.
cors:
allowed-origins: http://localhost:3000
allowed-methods: GET,POST,PUT,DELETE,PATCH,OPTIONS
allowed-headers: '*'
CorsConfig.java - 설정 빈 생성@ConfigurationProperties를 사용해 yml 값을 읽어와 CorsConfigurationSource 빈을 생성합니다.
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "cors")
public class CorsConfig {
private List<String> allowedOrigins;
private List<String> allowedMethods;
private List<String> allowedHeaders;
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(allowedOrigins);
config.setAllowedMethods(allowedMethods);
config.setAllowedHeaders(allowedHeaders);
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
SecurityConfig.java - 자동 설정 적용.cors(Customizer.withDefaults()) 한 줄만으로 위에서 생성된 빈을 자동으로 적용합니다.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.cors(Customizer.withDefaults()) // 자동으로 CorsConfigurationSource 빈을 찾아 적용
// ... 기타 설정
.build();
}
}
API의 역할(예: 일반 사용자용, 관리자용)에 따라 여러 개의 다른 CORS 정책을 적용해야 할 때 사용하는 방식입니다.
/api/v1/**)는 웹 클라이언트의 접근을 허용합니다./api/admin/**)는 내부 관리자 대시보드나 특정 IP에서만 접근을 허용해야 합니다.각기 다른 CORS 설정을 담은 빈을 여러 개 만들고, SecurityFilterChain에서 필요한 설정을 명시적으로 주입받아 사용합니다. 이를 통해 명확한 의존 관계를 설정하고 세밀한 제어가 가능해집니다.
CorsConfig.java - 여러 개의 설정 빈 생성@Qualifier를 사용하여 각기 다른 CORS 설정 빈을 이름으로 구분하여 생성합니다.
@Configuration
public class CorsConfig {
@Bean
@Qualifier("appCorsSource")
public CorsConfigurationSource appCorsConfigurationSource() { /* 웹 클라이언트용 설정 */ }
@Bean
@Qualifier("adminCorsSource")
public CorsConfigurationSource adminCorsConfigurationSource() { /* 관리자용 설정 */ }
}
SecurityConfig.java - 필터 체인 분리 및 명시적 주입URL 패턴에 따라 SecurityFilterChain을 분리하고, @Qualifier를 통해 해당 필터 체인에 맞는 CorsConfigurationSource 빈을 명시적으로 주입합니다.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
// 일반 사용자 API 보안 설정
@Bean
@Order(1)
public SecurityFilterChain apiFilterChain(HttpSecurity http, @Qualifier("appCorsSource") CorsConfigurationSource corsSource) throws Exception {
http
.securityMatcher("/api/v1/**")
.cors(cors -> cors.configurationSource(corsSource)) // 'appCorsSource' 명시적 사용
// ...
return http.build();
}
// 관리자 API 보안 설정
@Bean
@Order(2)
public SecurityFilterChain adminFilterChain(HttpSecurity http, @Qualifier("adminCorsSource") CorsConfigurationSource corsSource) throws Exception {
http
.securityMatcher("/api/admin/**")
.cors(cors -> cors.configurationSource(corsSource)) // 'adminCorsSource' 명시적 사용
// ...
return http.build();
}
}
| 구분 | 기본 설정 (암시적) | 고급 설정 (명시적) |
|---|---|---|
| 키워드 | Customizer.withDefaults() | 파라미터로 CorsConfigurationSource 주입 |
| 장점 | 간결함, 낮은 결합도 | 명확함, 세밀한 제어 |
| 적합한 상황 | 단일 CORS 정책 | 다중 CORS 정책, 복잡한 보안 규칙 |
프로젝트 초기에는 기본 설정으로 시작하여 단순함을 유지하고, 기능이 확장되어 API 그룹별로 다른 보안 정책이 필요해지는 시점에 자연스럽게 고급 설정으로 리팩토링하는 것이 좋습니다.