From 7d1c0c8faf271d3fde62e768918567a9a4b5ad9a Mon Sep 17 00:00:00 2001 From: sobinMoon Date: Mon, 18 Aug 2025 17:20:19 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EC=9D=B4=EC=8A=88=20?= =?UTF-8?q?=EB=8B=B4=EB=8B=B9=EC=9E=90=20=EC=A1=B0=ED=9A=8C=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Veco/domain/issue/service/IssueQueryService.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java b/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java index d441459a..2bb15aca 100644 --- a/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java +++ b/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java @@ -250,17 +250,19 @@ public Pageable> getIssuesByTeamId( // 담당자가 없는 이슈의 개수 조회 Long unassignedCount = issueRepository.findUnassignedIssuesCountByTeamId(teamId); + map.keySet().stream().sorted().toList(); map.put("담당자 없음", Math.toIntExact(unassignedCount)); - managers.add("담당자 없음"); + List sortedManagersList = map.keySet().stream().sorted().collect(Collectors.toList()); + sortedManagersList.addFirst("담당자 없음"); // firstCursor가 담당자 리스트에 포함되어있는지 확인 - if (!managers.contains(firstCursor)) { + if (!sortedManagersList.contains(firstCursor)) { // 없으면 담당자 없음부터 firstCursor = "담당자 없음"; } // 담당자 별 데이터 분류 - for (String filter : map.keySet().stream().sorted().toList()) { + for (String filter : sortedManagersList) { List result = new ArrayList<>(); // firstCursor가 일치할 때, 조회 시작 From 09a06450663cfd67ea84c298d930b2117bc97711 Mon Sep 17 00:00:00 2001 From: sobinMoon Date: Mon, 18 Aug 2025 17:24:19 +0900 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EC=9D=B4=EC=8A=88=20?= =?UTF-8?q?=EB=8B=B4=EB=8B=B9=EC=9E=90=20=EC=A1=B0=ED=9A=8C=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/Veco/domain/issue/service/IssueQueryService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java b/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java index 2bb15aca..e5a6374c 100644 --- a/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java +++ b/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java @@ -250,9 +250,8 @@ public Pageable> getIssuesByTeamId( // 담당자가 없는 이슈의 개수 조회 Long unassignedCount = issueRepository.findUnassignedIssuesCountByTeamId(teamId); - map.keySet().stream().sorted().toList(); - map.put("담당자 없음", Math.toIntExact(unassignedCount)); List sortedManagersList = map.keySet().stream().sorted().collect(Collectors.toList()); + map.put("담당자 없음", Math.toIntExact(unassignedCount)); sortedManagersList.addFirst("담당자 없음"); // firstCursor가 담당자 리스트에 포함되어있는지 확인 From 82353923c9f8d11f658e5a73c1fec4339d7552a3 Mon Sep 17 00:00:00 2001 From: sobinMoon Date: Mon, 18 Aug 2025 18:09:03 +0900 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EC=9D=B4=EC=8A=88=20?= =?UTF-8?q?=EB=AA=A9=ED=91=9C=20=EC=A1=B0=ED=9A=8C=20=EC=88=9C=EC=84=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Veco/domain/issue/service/IssueQueryService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java b/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java index e5a6374c..305eb66e 100644 --- a/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java +++ b/src/main/java/com/example/Veco/domain/issue/service/IssueQueryService.java @@ -321,16 +321,18 @@ public Pageable> getIssuesByTeamId( // 목표가 없는 이슈의 개수 조회 Long noGoalCount = issueRepository.findNoGoalIssuesCountByTeamId(teamId); + List sortedGoalsList = map.keySet().stream().sorted().collect(Collectors.toList()); map.put("목표 없음", Math.toIntExact(noGoalCount)); + sortedGoalsList.addFirst("목표 없음"); // firstCursor가 목표 리스트에 포함되어있는지 확인 - if (!goals.contains(firstCursor)) { + if (!sortedGoalsList.contains(firstCursor)) { // 없으면 목표 없음부터 firstCursor = "목표 없음"; } // 목표 별 데이터 분류 - for (String filter : map.keySet().stream().sorted().toList()) { + for (String filter : sortedGoalsList) { List result = new ArrayList<>(); // firstCursor가 일치할 때, 조회 시작 From 8e7b2e0ef73b44e3a8cb65395c6d85e65d68f43e Mon Sep 17 00:00:00 2001 From: rlawngjs0313 Date: Mon, 18 Aug 2025 18:35:22 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20develop=20?= =?UTF-8?q?=ED=99=98=EA=B2=BD=20=EB=A6=AC=EB=8B=A4=EC=9D=B4=EB=A0=89?= =?UTF-8?q?=ED=8A=B8=20=EB=B3=80=EA=B2=BD=20(web.vecoservice.shop=20->=20l?= =?UTF-8?q?ocalhost:5173)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/auth/oauth2/handler/OAuth2SuccessHandler.java | 2 +- .../java/com/example/Veco/global/config/SecurityConfig.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/Veco/global/auth/oauth2/handler/OAuth2SuccessHandler.java b/src/main/java/com/example/Veco/global/auth/oauth2/handler/OAuth2SuccessHandler.java index ac0d9f6a..0d645649 100644 --- a/src/main/java/com/example/Veco/global/auth/oauth2/handler/OAuth2SuccessHandler.java +++ b/src/main/java/com/example/Veco/global/auth/oauth2/handler/OAuth2SuccessHandler.java @@ -72,7 +72,7 @@ public void onAuthenticationSuccess( memberCommandService.saveMember(member); // 로딩 화면으로 리다이렉트 - redirectURL = UriComponentsBuilder.fromUriString("https://web.vecoservice.shop/onboarding/loading") + redirectURL = UriComponentsBuilder.fromUriString("http://localhost:5173/onboarding/loading") .build() .encode(StandardCharsets.UTF_8) .toUriString(); diff --git a/src/main/java/com/example/Veco/global/config/SecurityConfig.java b/src/main/java/com/example/Veco/global/config/SecurityConfig.java index ab5eacce..914db25a 100644 --- a/src/main/java/com/example/Veco/global/config/SecurityConfig.java +++ b/src/main/java/com/example/Veco/global/config/SecurityConfig.java @@ -50,7 +50,7 @@ protected SecurityFilterChain configure(HttpSecurity http) throws Exception { .httpBasic(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) .addFilterBefore(jwtAuthFilter(), UsernamePasswordAuthenticationFilter.class) - .logout(logout -> logout.logoutSuccessUrl("https://web.vecoservice.shop/onboarding")) + .logout(logout -> logout.logoutSuccessUrl("http://localhost:5173/onboarding")) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .oauth2Login(oauth2 -> oauth2 @@ -58,13 +58,13 @@ protected SecurityFilterChain configure(HttpSecurity http) throws Exception { .authorizationRequestRepository(new HttpSessionOAuth2AuthorizationRequestRepository()) .authorizationRequestResolver(customAuthorizationRequestResolver) ) - .loginPage("https://web.vecoservice.shop/onboarding") + .loginPage("http://localhost:5173/onboarding") .successHandler(oAuth2SuccessHandler) .userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService)) .failureHandler((request, response, exception) -> { // 로그인 실패 시 처리 로직 log.error("OAuth2 로그인 실패: {}", exception.getMessage()); - response.sendRedirect("https://web.vecoservice.shop/onboarding"); + response.sendRedirect("http://localhost:5173/onboarding"); }) ); return http.build(); From 0a7627cf362cba72168a18a7e7983e7757cacdfc Mon Sep 17 00:00:00 2001 From: sobinMoon Date: Mon, 18 Aug 2025 19:06:05 +0900 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=90=9B=20fix:=20JWT=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=97=90=EB=9F=AC=20=EC=9D=91=EB=8B=B5=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 --- .../global/auth/jwt/filter/JwtAuthFilter.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/Veco/global/auth/jwt/filter/JwtAuthFilter.java b/src/main/java/com/example/Veco/global/auth/jwt/filter/JwtAuthFilter.java index a4b73d2f..d0e8b319 100644 --- a/src/main/java/com/example/Veco/global/auth/jwt/filter/JwtAuthFilter.java +++ b/src/main/java/com/example/Veco/global/auth/jwt/filter/JwtAuthFilter.java @@ -1,11 +1,13 @@ package com.example.Veco.global.auth.jwt.filter; +import com.example.Veco.global.apiPayload.ApiResponse; import com.example.Veco.global.auth.jwt.exception.CustomJwtException; import com.example.Veco.global.auth.jwt.exception.code.JwtErrorCode; import com.example.Veco.global.auth.jwt.util.JwtUtil; import com.example.Veco.global.auth.user.exception.UserException; import com.example.Veco.global.auth.user.exception.code.UserErrorCode; import com.example.Veco.global.auth.user.service.CustomUserDetailsService; +import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.MalformedJwtException; import jakarta.servlet.FilterChain; @@ -15,6 +17,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -23,7 +26,9 @@ import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.time.LocalDateTime; import java.util.Arrays; +import java.util.Map; @Slf4j @RequiredArgsConstructor @@ -31,6 +36,7 @@ public class JwtAuthFilter extends OncePerRequestFilter { private final JwtUtil jwtUtil; private final CustomUserDetailsService customUserDetailsService; + private final ObjectMapper objectMapper = new ObjectMapper(); private static final AntPathMatcher pathMatcher = new AntPathMatcher(); private static final String[] excludePaths = {"/healthcheck", "/api/test/login/", "/api/token/reissue", "/login-test.html", @@ -76,11 +82,27 @@ protected void doFilterInternal( } filterChain.doFilter(request, response); } catch (ExpiredJwtException e) { - throw new CustomJwtException(JwtErrorCode.JWT_EXPIRED_TOKEN); + log.error("JWT 토큰 만료: {}", e.getMessage()); + sendErrorResponse(response, JwtErrorCode.JWT_EXPIRED_TOKEN); } catch (MalformedJwtException e) { - throw new CustomJwtException(JwtErrorCode.JWT_MALFORMED_TOKEN); + log.error("JWT 형식 오류: {}", e.getMessage()); + sendErrorResponse(response, JwtErrorCode.JWT_MALFORMED_TOKEN); } catch (UserException e) { throw new UserException(UserErrorCode.USER_NOT_FOUND); } } + + private void sendErrorResponse(HttpServletResponse response, JwtErrorCode errorCode) throws IOException { + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(errorCode.getHttpStatus().value()); + + objectMapper.writeValue( + response.getOutputStream(), + ApiResponse.onFailure( + errorCode.getCode(), + errorCode.getMessage(), + null + ) + ); + } } From 83762152c342fe2052be6cd584c0b073c1e0d768 Mon Sep 17 00:00:00 2001 From: finger9999 <161580182+finger9999@users.noreply.github.com> Date: Tue, 19 Aug 2025 02:20:11 +0800 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20=EC=9B=8C=ED=81=AC=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workspace/controller/SettingRestController.java | 10 +++++++++- .../workspace/service/WorkspaceCommandServiceImpl.java | 4 ---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/Veco/domain/workspace/controller/SettingRestController.java b/src/main/java/com/example/Veco/domain/workspace/controller/SettingRestController.java index fa670513..860d052e 100644 --- a/src/main/java/com/example/Veco/domain/workspace/controller/SettingRestController.java +++ b/src/main/java/com/example/Veco/domain/workspace/controller/SettingRestController.java @@ -158,7 +158,15 @@ public ApiResponse> getWo List result = workspaceQueryService.getWorkspaceMembers(member); - return ApiResponse.onSuccess(result); + List sorted = result.stream() + .sorted((m1, m2) -> { + if (m1.getMemberId().equals(member.getId())) return -1; //나 자신은 항상 상단 + if (m2.getMemberId().equals(member.getId())) return 1; + return m1.getJoinedAt().compareTo(m2.getJoinedAt()); //참여일 순 + }) + .toList(); + + return ApiResponse.onSuccess(sorted); } /** diff --git a/src/main/java/com/example/Veco/domain/workspace/service/WorkspaceCommandServiceImpl.java b/src/main/java/com/example/Veco/domain/workspace/service/WorkspaceCommandServiceImpl.java index 64a6370a..82e814ff 100644 --- a/src/main/java/com/example/Veco/domain/workspace/service/WorkspaceCommandServiceImpl.java +++ b/src/main/java/com/example/Veco/domain/workspace/service/WorkspaceCommandServiceImpl.java @@ -135,10 +135,6 @@ public void updateTeamOrder(WorkSpace workspace, List teamIdList) { @Override public WorkspaceResponseDTO.CreateWorkspaceResponseDto createWorkspace(Member member, WorkspaceRequestDTO.WorkspaceRequestDto request) { - // 1. 워크스페이스 이름 중복 검사 - if (workspaceRepository.existsByName(request.getWorkspaceName())) { - throw new WorkspaceHandler(WorkspaceErrorStatus._DUPLICATE_WORKSPACE_NAME); - } // 2. 이미 워크스페이스가 있으면 예외 if (member.getWorkSpace() != null) { throw new WorkspaceHandler(WorkspaceErrorStatus._WORKSPACE_DUPLICATED); From 97b8d538aa030b2242e8ac16827ea9bd84f7ca8a Mon Sep 17 00:00:00 2001 From: sobinMoon Date: Wed, 20 Aug 2025 12:20:57 +0900 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EB=A7=8C=EB=A3=8C=20=EC=8B=9C=EC=9D=98=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/jwt/controller/JwtController.java | 2 +- .../global/auth/jwt/filter/JwtAuthFilter.java | 10 ++++- .../Veco/global/auth/jwt/util/JwtUtil.java | 2 + .../Veco/global/config/SecurityConfig.java | 44 ++++++++++--------- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/example/Veco/global/auth/jwt/controller/JwtController.java b/src/main/java/com/example/Veco/global/auth/jwt/controller/JwtController.java index b404ec74..7b11d26d 100644 --- a/src/main/java/com/example/Veco/global/auth/jwt/controller/JwtController.java +++ b/src/main/java/com/example/Veco/global/auth/jwt/controller/JwtController.java @@ -11,7 +11,6 @@ import com.example.Veco.global.auth.jwt.util.JwtUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; @@ -53,6 +52,7 @@ public ApiResponse reissue(HttpServletRequest request, HttpServletResp ResponseCookie refreshTokenCookie = jwtUtil.createRefreshTokenCookie(newRefreshToken); response.addHeader("Set-Cookie", refreshTokenCookie.toString()); } + log.info("토큰 재발급 성공: {}", newAccessToken); return ApiResponse.onSuccess(TokenConverter.toTokenDTO(newAccessToken)); } catch (CustomJwtException e) { log.error("토큰 재발급 실패: {}", e.getMessage()); diff --git a/src/main/java/com/example/Veco/global/auth/jwt/filter/JwtAuthFilter.java b/src/main/java/com/example/Veco/global/auth/jwt/filter/JwtAuthFilter.java index d0e8b319..dcc75183 100644 --- a/src/main/java/com/example/Veco/global/auth/jwt/filter/JwtAuthFilter.java +++ b/src/main/java/com/example/Veco/global/auth/jwt/filter/JwtAuthFilter.java @@ -68,7 +68,15 @@ protected void doFilterInternal( // Bearer이면 추출 token = token.replace("Bearer ", ""); // AccessToken 검증하기: 올바른 토큰이면 - if (jwtUtil.isAccessTokenValid(token)) { + if (!jwtUtil.isAccessTokenValid(token)) { + log.error("JWT 토큰이 유효하지 않습니다: {}", token); + sendErrorResponse(response, JwtErrorCode.JWT_INVALID_TOKEN); + return; + } else if (jwtUtil.isTokenExpired(token)) { + log.error("JWT 토큰이 만료되었습니다: {}", token); + sendErrorResponse(response, JwtErrorCode.JWT_EXPIRED_TOKEN); + return; + } else { // 토큰에서 이메일 추출 String uid = jwtUtil.getUsername(token); UserDetails user = customUserDetailsService.loadUserByUsername(uid); diff --git a/src/main/java/com/example/Veco/global/auth/jwt/util/JwtUtil.java b/src/main/java/com/example/Veco/global/auth/jwt/util/JwtUtil.java index fd65c2de..3dd3ba0d 100644 --- a/src/main/java/com/example/Veco/global/auth/jwt/util/JwtUtil.java +++ b/src/main/java/com/example/Veco/global/auth/jwt/util/JwtUtil.java @@ -103,11 +103,13 @@ public boolean isAccessTokenValid(String token) { try { // 토큰이 블랙리스트에 존재하는지 확인 if (isBlackList(token)){ + log.info("토큰이 블랙리스트에 존재합니다: {}", token); return false; } getClaims(token); return true; } catch (CustomJwtException e) { + log.error("토큰 유효성 검사 실패: {}", e.getMessage()); return false; } } diff --git a/src/main/java/com/example/Veco/global/config/SecurityConfig.java b/src/main/java/com/example/Veco/global/config/SecurityConfig.java index 914db25a..2a5516f7 100644 --- a/src/main/java/com/example/Veco/global/config/SecurityConfig.java +++ b/src/main/java/com/example/Veco/global/config/SecurityConfig.java @@ -3,21 +3,19 @@ import com.example.Veco.global.auth.jwt.filter.JwtAuthFilter; import com.example.Veco.global.auth.jwt.util.JwtUtil; import com.example.Veco.global.auth.oauth2.handler.OAuth2SuccessHandler; -import com.example.Veco.global.auth.oauth2.resolver.CustomAuthorizationRequestResolver; import com.example.Veco.global.auth.oauth2.service.OAuth2UserService; import com.example.Veco.global.auth.user.service.CustomUserDetailsService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; 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.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfigurationSource; @@ -31,42 +29,46 @@ public class SecurityConfig { private final CustomUserDetailsService customUserDetailsService; private final OAuth2UserService customOAuth2UserService; private final OAuth2SuccessHandler oAuth2SuccessHandler; - private final CustomAuthorizationRequestResolver customAuthorizationRequestResolver; private final JwtUtil jwtUtil; private final CorsConfigurationSource corsConfigurationSource; @Bean - protected SecurityFilterChain configure(HttpSecurity http) throws Exception { + @Order(1) + public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception { http + .securityMatcher("/api/**", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-resources/**") .cors(cors -> cors.configurationSource(corsConfigurationSource)) .csrf(AbstractHttpConfigurer::disable) - .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) .authorizeHttpRequests(auth -> auth - .requestMatchers("/api/test/**", "/api/teams/*/externals/**", "/api/teams/*/externals", "/api/test/login", "/api/token/reissue", "/login-test.html", "/v3/api-docs/**", "/swagger-ui/**", - "/swagger-resources/**", "/css/**", "/images/**", "/healthcheck", - "/js/**", "/h2-console/**", "/profile","/workspace/create-url","/slack/callback", "/github/**","/api/github/**").permitAll() + .requestMatchers("/api/test/**", "/api/token/reissue", + "/v3/api-docs/**", "/swagger-ui/**", "/swagger-resources/**").permitAll() .anyRequest().authenticated() ) - .httpBasic(AbstractHttpConfigurer::disable) - .formLogin(AbstractHttpConfigurer::disable) .addFilterBefore(jwtAuthFilter(), UsernamePasswordAuthenticationFilter.class) - .logout(logout -> logout.logoutSuccessUrl("http://localhost:5173/onboarding")) .sessionManagement(session -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + + return http.build(); + } + + // 웹용 SecurityFilterChain (OAuth2만) + @Bean + @Order(2) + public SecurityFilterChain webFilterChain(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests(auth -> auth + .requestMatchers("/healthcheck", "/css/**", "/js/**", "/images/**").permitAll() + .anyRequest().authenticated() + ) .oauth2Login(oauth2 -> oauth2 - .authorizationEndpoint(config -> config - .authorizationRequestRepository(new HttpSessionOAuth2AuthorizationRequestRepository()) - .authorizationRequestResolver(customAuthorizationRequestResolver) - ) - .loginPage("http://localhost:5173/onboarding") + .loginPage("https://web.vecoservice.shop/onboarding") .successHandler(oAuth2SuccessHandler) .userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService)) .failureHandler((request, response, exception) -> { - // 로그인 실패 시 처리 로직 - log.error("OAuth2 로그인 실패: {}", exception.getMessage()); - response.sendRedirect("http://localhost:5173/onboarding"); + response.sendRedirect("https://web.vecoservice.shop/onboarding"); }) ); + return http.build(); }