66import org .springframework .context .annotation .Bean ;
77import org .springframework .context .annotation .Configuration ;
88import org .springframework .http .HttpHeaders ;
9+ import org .springframework .http .HttpMethod ; // ✅ 추가
910import org .springframework .http .MediaType ;
1011import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
1112import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
1920import org .springframework .web .reactive .function .client .WebClient ;
2021import util .JwtTokenProvider ;
2122
23+ // ⚠️ JwtAuthenticationFilter import는 프로젝트 경로에 맞게 유지하세요.
24+ // import com.dmu.debug_visual.config.JwtAuthenticationFilter; (예시)
25+
2226import java .util .List ;
2327
2428@ Configuration
@@ -35,24 +39,40 @@ public class SecurityConfig {
3539 @ Bean
3640 public SecurityFilterChain filterChain (HttpSecurity http ) throws Exception {
3741 http
38- .cors (cors -> cors .configurationSource (corsConfigurationSource ()))
39- .csrf (csrf -> csrf .disable ())
40- .authorizeHttpRequests (auth -> auth
41- .requestMatchers (
42- "/api/users/login" ,
43- "/api/users/signup" ,
44- "/swagger-ui/**" ,
45- "/v3/api-docs/**"
46- ).permitAll ()
47- .requestMatchers ("/api/admin/**" ).hasRole ("ADMIN" )
48- .requestMatchers ("/api/posts/**" ).hasAnyRole ("USER" , "ADMIN" )
49- .requestMatchers ("/api/notifications/**" ).hasAnyRole ("USER" , "ADMIN" )
50- .anyRequest ().authenticated ()
51- )
52- .addFilterBefore (new JwtAuthenticationFilter (jwtTokenProvider , userRepository ),
53- UsernamePasswordAuthenticationFilter .class )
54- .formLogin (form -> form .disable ())
55- .httpBasic (basic -> basic .disable ());
42+ // CORS 우선 적용
43+ .cors (cors -> cors .configurationSource (corsConfigurationSource ()))
44+ // REST API라면 CSRF 비활성
45+ .csrf (csrf -> csrf .disable ())
46+ .authorizeHttpRequests (auth -> auth
47+ // ✅ 프리플라이트 전역 허용 (중요)
48+ .requestMatchers (HttpMethod .OPTIONS , "/**" ).permitAll ()
49+
50+ // ✅ 공개 엔드포인트
51+ .requestMatchers (
52+ "/api/users/login" ,
53+ "/api/users/signup" ,
54+ "/swagger-ui/**" ,
55+ "/swagger-ui.html" ,
56+ "/v3/api-docs/**" ,
57+ "/actuator/health" ,
58+ "/healthz" ,
59+ "/public/**"
60+ ).permitAll ()
61+
62+ // 역할 기반
63+ .requestMatchers ("/api/admin/**" ).hasRole ("ADMIN" )
64+ .requestMatchers ("/api/posts/**" ).hasAnyRole ("USER" , "ADMIN" )
65+ .requestMatchers ("/api/notifications/**" ).hasAnyRole ("USER" , "ADMIN" )
66+
67+ // 나머지는 인증 필요
68+ .anyRequest ().authenticated ()
69+ )
70+ // JWT 필터 (위치 유지)
71+ .addFilterBefore (new JwtAuthenticationFilter (jwtTokenProvider , userRepository ),
72+ UsernamePasswordAuthenticationFilter .class )
73+ // 폼/기본 인증 비활성
74+ .formLogin (form -> form .disable ())
75+ .httpBasic (basic -> basic .disable ());
5676
5777 return http .build ();
5878 }
@@ -62,6 +82,7 @@ public PasswordEncoder passwordEncoder() {
6282 return new BCryptPasswordEncoder ();
6383 }
6484
85+ // 백엔드 → 파이썬 컴파일러 호출용 WebClient
6586 @ Bean
6687 public WebClient webClient () {
6788 return WebClient .builder ()
@@ -70,15 +91,22 @@ public WebClient webClient() {
7091 .build ();
7192 }
7293
94+ // ✅ CORS: 프록시(Nginx)와 값 일치 — zivorp.com만 허용(+ www, http/https)
7395 @ Bean
7496 public CorsConfigurationSource corsConfigurationSource () {
7597 CorsConfiguration config = new CorsConfiguration ();
76- config .setAllowedOriginPatterns (List .of ("*" ));
77- // 또는 특정 도메인만 허용할 경우:
78- // config.setAllowedOrigins(List.of("https://zivorp.com", "http://zivorp.com"));
79- config .setAllowedMethods (List .of ("GET" , "POST" , "PUT" , "DELETE" , "OPTIONS" ));
80- config .setAllowedHeaders (List .of ("*" ));
98+ // AllowedOriginPatterns("*") + Credentials(true)는 브라우저에서 막히기 쉬움.
99+ // 명시적으로 허용 도메인만 지정하세요.
100+ config .setAllowedOrigins (List .of (
101+ "https://zivorp.com" ,
102+ "http://zivorp.com" ,
103+ "https://www.zivorp.com" ,
104+ "http://www.zivorp.com"
105+ ));
106+ config .setAllowedMethods (List .of ("GET" , "POST" , "PUT" , "PATCH" , "DELETE" , "OPTIONS" ));
107+ config .setAllowedHeaders (List .of ("Authorization" , "Content-Type" , "X-Requested-With" ));
81108 config .setAllowCredentials (true );
109+ config .setMaxAge (3600L );
82110
83111 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource ();
84112 source .registerCorsConfiguration ("/**" , config );
0 commit comments