From 12fb40bb340955df497b4bf2517a37184a736716 Mon Sep 17 00:00:00 2001 From: Joon9750 Date: Sun, 18 May 2025 15:36:56 +0900 Subject: [PATCH 1/7] =?UTF-8?q?[Fix]=20cors=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring_rest_api/security/JwtAuthenticationFilter.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java b/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java index e7f4167..49da003 100644 --- a/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java @@ -12,6 +12,7 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; +import org.springframework.web.cors.CorsUtils; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; @@ -38,6 +39,11 @@ protected void doFilterInternal( return; } + if(CorsUtils.isPreFlightRequest(request)) { + response.setStatus(HttpServletResponse.SC_OK); + return; + } + jwt = authHeader.substring(7); userEmail = jwtService.extractUsername(jwt); From 47709f70095d592d8c82e8bbc66dcec6d7217523 Mon Sep 17 00:00:00 2001 From: Joon9750 Date: Sun, 18 May 2025 15:48:14 +0900 Subject: [PATCH 2/7] =?UTF-8?q?[Fix]=20cors=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/SecurityConfig.java | 19 +++++++++++++++++++ .../security/JwtAuthenticationFilter.java | 17 ++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/_1/spring_rest_api/config/SecurityConfig.java b/src/main/java/com/_1/spring_rest_api/config/SecurityConfig.java index 4b249a2..eb1338b 100644 --- a/src/main/java/com/_1/spring_rest_api/config/SecurityConfig.java +++ b/src/main/java/com/_1/spring_rest_api/config/SecurityConfig.java @@ -9,6 +9,11 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.Arrays; @EnableWebSecurity @Configuration @@ -26,6 +31,7 @@ public SecurityConfig(OAuth2SuccessHandler oAuth2SuccessHandler, JwtAuthenticati public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) + .cors(cors -> cors.configurationSource(corsConfigurationSource())) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .anyRequest().permitAll() @@ -41,4 +47,17 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti return http.build(); } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(Arrays.asList("*")); // 또는 특정 도메인 지정 + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); + configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Requested-With")); + configuration.setMaxAge(3600L); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } } diff --git a/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java b/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java index 49da003..a96c650 100644 --- a/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java @@ -30,15 +30,22 @@ protected void doFilterInternal( @NonNull HttpServletResponse response, @NonNull FilterChain filterChain ) throws ServletException, IOException { - final String authHeader = request.getHeader("Authorization"); - final String jwt; - final String userEmail; + // CORS 헤더 추가 + response.setHeader("Access-Control-Allow-Origin", "*"); // 또는 특정 도메인 + response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); + response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With"); + response.setHeader("Access-Control-Max-Age", "3600"); - if (authHeader == null || !authHeader.startsWith("Bearer ")) { - filterChain.doFilter(request, response); + // OPTIONS 메서드 처리 (사전 요청) + if (CorsUtils.isPreFlightRequest(request)) { + response.setStatus(HttpServletResponse.SC_OK); return; } + final String authHeader = request.getHeader("Authorization"); + final String jwt; + final String userEmail; + if(CorsUtils.isPreFlightRequest(request)) { response.setStatus(HttpServletResponse.SC_OK); return; From c80d4387dd5ade77c25ed85cd76ac6704315d8db Mon Sep 17 00:00:00 2001 From: Joon9750 Date: Sun, 18 May 2025 15:58:07 +0900 Subject: [PATCH 3/7] =?UTF-8?q?[Fix]=20header=20null=20error=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring_rest_api/security/JwtAuthenticationFilter.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java b/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java index a96c650..d2af5df 100644 --- a/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java @@ -43,6 +43,13 @@ protected void doFilterInternal( } final String authHeader = request.getHeader("Authorization"); + + // 여기서 authHeader가 null인지 확인하고 null이면 다음 필터로 진행 + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + filterChain.doFilter(request, response); + return; + } + final String jwt; final String userEmail; From 855cb00b1889272110cd1fa2c7f1160cff08d12b Mon Sep 17 00:00:00 2001 From: dmori Date: Sun, 18 May 2025 16:47:25 +0900 Subject: [PATCH 4/7] =?UTF-8?q?[Fix]=20https/http=20=ED=98=BC=ED=95=A9=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring_rest_api/config/SwaggerConfig.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/_1/spring_rest_api/config/SwaggerConfig.java b/src/main/java/com/_1/spring_rest_api/config/SwaggerConfig.java index 90f12e3..7bfaaeb 100644 --- a/src/main/java/com/_1/spring_rest_api/config/SwaggerConfig.java +++ b/src/main/java/com/_1/spring_rest_api/config/SwaggerConfig.java @@ -3,17 +3,35 @@ import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.List; + @Configuration // 스프링 실행시 설정파일 읽어드리기 위한 어노테이션 public class SwaggerConfig { @Bean public OpenAPI openAPI() { + // JWT 보안 스키마 정의 + SecurityScheme jwtScheme = new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .in(SecurityScheme.In.HEADER) + .name("Authorization"); + + // 보안 요구사항 설정 + SecurityRequirement securityRequirement = new SecurityRequirement().addList("JWT"); + return new OpenAPI() - .components(new Components()) - .info(apiInfo()); + .components(new Components().addSecuritySchemes("JWT", jwtScheme)) + .addSecurityItem(securityRequirement) + .info(apiInfo()) + .servers(List.of(new Server().url("https://spring-container-620597935007.us-central1.run.app"))); // HTTPS 명시 } private Info apiInfo() { From 33ae594465d340589a5a3654b1a211a7f387892f Mon Sep 17 00:00:00 2001 From: Joon9750 Date: Sat, 31 May 2025 00:41:38 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[Modify]=20classroom=20cascade=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/_1/spring_rest_api/entity/Course.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/_1/spring_rest_api/entity/Course.java b/src/main/java/com/_1/spring_rest_api/entity/Course.java index 1d52219..b5203df 100644 --- a/src/main/java/com/_1/spring_rest_api/entity/Course.java +++ b/src/main/java/com/_1/spring_rest_api/entity/Course.java @@ -35,7 +35,7 @@ public class Course extends BaseTimeEntity { @Column(name = "description", columnDefinition = "TEXT") private String description; - @OneToMany(mappedBy = "course") + @OneToMany(mappedBy = "course", cascade = CascadeType.ALL, orphanRemoval = true) @Builder.Default private List weeks = new ArrayList<>(); From 373e5f409b6771afde9d6d6eaa87232a981d2c5b Mon Sep 17 00:00:00 2001 From: Joon9750 Date: Sat, 31 May 2025 00:41:56 +0900 Subject: [PATCH 6/7] =?UTF-8?q?[Modify]=20classroom=20cascade=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/_1/spring_rest_api/entity/Course.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/_1/spring_rest_api/entity/Course.java b/src/main/java/com/_1/spring_rest_api/entity/Course.java index b5203df..19415fe 100644 --- a/src/main/java/com/_1/spring_rest_api/entity/Course.java +++ b/src/main/java/com/_1/spring_rest_api/entity/Course.java @@ -35,7 +35,7 @@ public class Course extends BaseTimeEntity { @Column(name = "description", columnDefinition = "TEXT") private String description; - @OneToMany(mappedBy = "course", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "course", cascade = CascadeType.ALL) @Builder.Default private List weeks = new ArrayList<>(); From 82dc04a026e4b8c59dd50b5afb47f6a5ee51778e Mon Sep 17 00:00:00 2001 From: Joon9750 Date: Sat, 31 May 2025 00:45:00 +0900 Subject: [PATCH 7/7] =?UTF-8?q?[Fix]=20github=EA=B3=BC=20=EB=8F=99?= =?UTF-8?q?=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/SecurityConfig.java | 21 +---------------- .../security/JwtAuthenticationFilter.java | 23 ++----------------- 2 files changed, 3 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/_1/spring_rest_api/config/SecurityConfig.java b/src/main/java/com/_1/spring_rest_api/config/SecurityConfig.java index 6702187..3be0fa5 100644 --- a/src/main/java/com/_1/spring_rest_api/config/SecurityConfig.java +++ b/src/main/java/com/_1/spring_rest_api/config/SecurityConfig.java @@ -9,11 +9,6 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; - -import java.util.Arrays; @EnableWebSecurity @Configuration @@ -26,7 +21,6 @@ public class SecurityConfig { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) - .cors(cors -> cors.configurationSource(corsConfigurationSource())) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/public/auth/**", "/error", @@ -38,17 +32,4 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti return http.build(); } - - @Bean - public CorsConfigurationSource corsConfigurationSource() { - CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("*")); // 또는 특정 도메인 지정 - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); - configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Requested-With")); - configuration.setMaxAge(3600L); - - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); - return source; - } -} +} \ No newline at end of file diff --git a/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java b/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java index e83e173..49da003 100644 --- a/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/_1/spring_rest_api/security/JwtAuthenticationFilter.java @@ -30,31 +30,12 @@ protected void doFilterInternal( @NonNull HttpServletResponse response, @NonNull FilterChain filterChain ) throws ServletException, IOException { - // CORS 헤더 추가 - response.setHeader("Access-Control-Allow-Origin", "*"); // 또는 특정 도메인 - response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); - response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With"); - response.setHeader("Access-Control-Max-Age", "3600"); - - // OPTIONS 메서드 처리 (사전 요청) - if (CorsUtils.isPreFlightRequest(request)) { - response.setStatus(HttpServletResponse.SC_OK); - return; - } - final String authHeader = request.getHeader("Authorization"); - - // 여기서 authHeader가 null인지 확인하고 null이면 다음 필터로 진행 - if (authHeader == null || !authHeader.startsWith("Bearer ")) { - filterChain.doFilter(request, response); - return; - } - final String jwt; final String userEmail; - if(CorsUtils.isPreFlightRequest(request)) { - response.setStatus(HttpServletResponse.SC_OK); + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + filterChain.doFilter(request, response); return; }