diff --git a/analytics/src/main/java/com/ktds/hi/analytics/infra/config/SecurityConfig.java b/analytics/src/main/java/com/ktds/hi/analytics/infra/config/SecurityConfig.java index 1a43aa3..1c7aca7 100644 --- a/analytics/src/main/java/com/ktds/hi/analytics/infra/config/SecurityConfig.java +++ b/analytics/src/main/java/com/ktds/hi/analytics/infra/config/SecurityConfig.java @@ -7,6 +7,9 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfigurationSource; + +import lombok.RequiredArgsConstructor; /** * Analytics 서비스 보안 설정 클래스 @@ -14,12 +17,16 @@ import org.springframework.security.web.SecurityFilterChain; */ @Configuration @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { + private final CorsConfigurationSource corsConfigurationSource; + @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) + .cors(cors -> cors.configurationSource(corsConfigurationSource)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth // Swagger 관련 경로 모두 허용 diff --git a/analytics/src/main/resources/application.yml b/analytics/src/main/resources/application.yml index c18bf57..f9b1049 100644 --- a/analytics/src/main/resources/application.yml +++ b/analytics/src/main/resources/application.yml @@ -92,4 +92,4 @@ azure: ai-analysis-events: ${AZURE_EVENTHUB_AI_ANALYSIS_EVENTS:ai-analysis-events} storage: connection-string: ${AZURE_STORAGE_CONNECTION_STRING:DefaultEndpointsProtocol=https;AccountName=yourstorageaccount;AccountKey=your-storage-key;EndpointSuffix=core.windows.net} - container-name: ${AZURE_STORAGE_CONTAINER_NAME:eventhub-checkpoints} \ No newline at end of file + container-name: ${AZURE_STORAGE_CONTAINER_NAME:eventhub-checkpoints} diff --git a/common/src/main/java/com/ktds/hi/common/config/CorsConfig.java b/common/src/main/java/com/ktds/hi/common/config/CorsConfig.java new file mode 100644 index 0000000..3f14ba3 --- /dev/null +++ b/common/src/main/java/com/ktds/hi/common/config/CorsConfig.java @@ -0,0 +1,102 @@ +package com.ktds.hi.common.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.Arrays; +import java.util.List; + +/** + * 전체 서비스 통합 CORS 설정 클래스 + * 모든 마이크로서비스에서 공통으로 사용되는 CORS 정책을 정의 + */ +@Configuration +public class CorsConfig implements WebMvcConfigurer { + + @Value("${app.cors.allowed-origins:http://localhost:3000,http://localhost:8080,http://localhost:3001}") + private String allowedOrigins; + + @Value("${app.cors.allowed-methods:GET,POST,PUT,DELETE,PATCH,OPTIONS}") + private String allowedMethods; + + @Value("${app.cors.allowed-headers:*}") + private String allowedHeaders; + + @Value("${app.cors.exposed-headers:Authorization,X-Total-Count}") + private String exposedHeaders; + + @Value("${app.cors.allow-credentials:true}") + private boolean allowCredentials; + + @Value("${app.cors.max-age:3600}") + private long maxAge; + + /** + * WebMvcConfigurer를 통한 CORS 설정 + */ + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOriginPatterns(allowedOrigins.split(",")) + .allowedMethods(allowedMethods.split(",")) + .allowedHeaders(allowedHeaders.split(",")) + .exposedHeaders(exposedHeaders.split(",")) + .allowCredentials(allowCredentials) + .maxAge(maxAge); + } + + /** + * CorsConfigurationSource Bean 생성 + * Spring Security와 함께 사용되는 CORS 설정 + */ + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + + // Origin 설정 + List origins = Arrays.asList(allowedOrigins.split(",")); + configuration.setAllowedOriginPatterns(origins); + + // Method 설정 + List methods = Arrays.asList(allowedMethods.split(",")); + configuration.setAllowedMethods(methods); + + // Header 설정 + if ("*".equals(allowedHeaders)) { + configuration.addAllowedHeader("*"); + } else { + List headers = Arrays.asList(allowedHeaders.split(",")); + configuration.setAllowedHeaders(headers); + } + + // Exposed Headers 설정 + List exposed = Arrays.asList(exposedHeaders.split(",")); + configuration.setExposedHeaders(exposed); + + // Credentials 설정 + configuration.setAllowCredentials(allowCredentials); + + // Max Age 설정 + configuration.setMaxAge(maxAge); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + /** + * CorsFilter Bean 생성 + * 글로벌 CORS 필터로 사용 + */ + @Bean + public CorsFilter corsFilter() { + return new CorsFilter(corsConfigurationSource()); + } +} \ No newline at end of file diff --git a/common/src/main/resources/application-common.yml b/common/src/main/resources/application-common.yml index 32ccc51..04c052f 100644 --- a/common/src/main/resources/application-common.yml +++ b/common/src/main/resources/application-common.yml @@ -51,13 +51,12 @@ app: secret-key: ${JWT_SECRET_KEY:hiorder-secret-key-for-jwt-token-generation-2024-very-long-secret-key} access-token-validity: ${JWT_ACCESS_TOKEN_VALIDITY:3600000} # 1시간 refresh-token-validity: ${JWT_REFRESH_TOKEN_VALIDITY:604800000} # 7일 - # CORS 설정 cors: - allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3000,http://localhost:8080} + allowed-origins: ${CORS_ALLOWED_ORIGINS:http://20.214.126.84:80,http://localhost:8080} allowed-methods: ${CORS_ALLOWED_METHODS:GET,POST,PUT,DELETE,OPTIONS} allowed-headers: ${CORS_ALLOWED_HEADERS:*} - exposed-headers: ${CORS_EXPOSED_HEADERS:Authorization} + exposed-headers: ${CORS_EXPOSED_HEADERS:Authorization, X-Total-Count} allow-credentials: ${CORS_ALLOW_CREDENTIALS:true} max-age: ${CORS_MAX_AGE:3600} diff --git a/member/src/main/java/com/ktds/hi/member/config/SecurityConfig.java b/member/src/main/java/com/ktds/hi/member/config/SecurityConfig.java index ea30d1c..47fcf95 100644 --- a/member/src/main/java/com/ktds/hi/member/config/SecurityConfig.java +++ b/member/src/main/java/com/ktds/hi/member/config/SecurityConfig.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.ktds.hi.common.security.JwtTokenProvider; import com.ktds.hi.common.security.JwtAuthenticationFilter; import lombok.RequiredArgsConstructor; + +import org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpoint; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; @@ -16,6 +18,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfigurationSource; /** * Spring Security 설정 클래스 @@ -27,15 +30,17 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic public class SecurityConfig { private final JwtTokenProvider jwtTokenProvider; + private final CorsConfigurationSource corsConfigurationSource; /** * 보안 필터 체인 설정 * JWT 인증 방식을 사용하고 세션은 무상태로 관리 */ @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + public SecurityFilterChain filterChain(HttpSecurity http, ConditionsReportEndpoint conditionsReportEndpoint) throws Exception { http .csrf(csrf -> csrf.disable()) + .cors(cors -> cors.configurationSource(corsConfigurationSource)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(authz -> authz .requestMatchers("/api/auth/**", "/api/members/register", "/api/auth/login").permitAll() diff --git a/recommend/src/main/java/com/ktds/hi/recommend/infra/config/SecurityConfig.java b/recommend/src/main/java/com/ktds/hi/recommend/infra/config/SecurityConfig.java new file mode 100644 index 0000000..f1b3a0c --- /dev/null +++ b/recommend/src/main/java/com/ktds/hi/recommend/infra/config/SecurityConfig.java @@ -0,0 +1,52 @@ +package com.ktds.hi.recommend.infra.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfigurationSource; + +import lombok.RequiredArgsConstructor; + +/** + * Analytics 서비스 보안 설정 클래스 + * 테스트를 위해 모든 엔드포인트를 인증 없이 접근 가능하도록 설정 + */ +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final CorsConfigurationSource corsConfigurationSource; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + + + http + .csrf(AbstractHttpConfigurer::disable) + .cors(cors -> cors.configurationSource(corsConfigurationSource)) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(auth -> auth + // Swagger 관련 경로 모두 허용 + .requestMatchers("/swagger-ui.html","/swagger-ui/**", "/swagger-ui.html").permitAll() + .requestMatchers("/api-docs/**", "/v3/api-docs/**").permitAll() + .requestMatchers("/swagger-resources/**", "/webjars/**").permitAll() + + // Analytics API 모두 허용 (테스트용) + .requestMatchers("/api/analytics/**").permitAll() + .requestMatchers("/api/action-plans/**").permitAll() + + // Actuator 엔드포인트 허용 + .requestMatchers("/actuator/**").permitAll() + + // 기타 모든 요청 허용 (테스트용) + .anyRequest().permitAll() + ); + + return http.build(); + } +} diff --git a/recommend/src/main/resources/application.yml b/recommend/src/main/resources/application.yml index eff4854..6f8573a 100644 --- a/recommend/src/main/resources/application.yml +++ b/recommend/src/main/resources/application.yml @@ -132,7 +132,6 @@ management: springdoc: api-docs: path: /api-docs - enabled: true swagger-ui: path: /swagger-ui.html tags-sorter: alpha diff --git a/review/src/main/java/com/ktds/hi/review/infra/config/SecurityConfig.java b/review/src/main/java/com/ktds/hi/review/infra/config/SecurityConfig.java index 92a1a7f..6c66b1a 100644 --- a/review/src/main/java/com/ktds/hi/review/infra/config/SecurityConfig.java +++ b/review/src/main/java/com/ktds/hi/review/infra/config/SecurityConfig.java @@ -7,6 +7,9 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfigurationSource; + +import lombok.RequiredArgsConstructor; /** * Analytics 서비스 보안 설정 클래스 @@ -14,12 +17,16 @@ import org.springframework.security.web.SecurityFilterChain; */ @Configuration @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { + private final CorsConfigurationSource corsConfigurationSource; + @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) + .cors(cors -> cors.configurationSource(corsConfigurationSource)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth // Swagger 관련 경로 모두 허용 diff --git a/store/src/main/java/com/ktds/hi/store/config/SecurityConfig.java b/store/src/main/java/com/ktds/hi/store/config/SecurityConfig.java index 1beeacd..1c1d436 100644 --- a/store/src/main/java/com/ktds/hi/store/config/SecurityConfig.java +++ b/store/src/main/java/com/ktds/hi/store/config/SecurityConfig.java @@ -7,6 +7,9 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfigurationSource; + +import lombok.RequiredArgsConstructor; /** * Analytics 서비스 보안 설정 클래스 @@ -14,12 +17,16 @@ import org.springframework.security.web.SecurityFilterChain; */ @Configuration @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { + private final CorsConfigurationSource corsConfigurationSource; + @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) + .cors(cors -> cors.configurationSource(corsConfigurationSource)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth // Swagger 관련 경로 모두 허용