From dd6746b865e3c62b1ec27738b76b6d29605b1a79 Mon Sep 17 00:00:00 2001 From: seungwookc97 Date: Mon, 13 Oct 2025 10:29:31 +0900 Subject: [PATCH 1/4] =?UTF-8?q?chore:main=20=EB=B8=8C=EB=9E=9C=EC=B9=98=20?= =?UTF-8?q?=EB=B3=91=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/back/domain/user/dto/RefreshTokenResDto.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/back/domain/user/dto/RefreshTokenResDto.java b/src/main/java/com/back/domain/user/dto/RefreshTokenResDto.java index 3e705940..5131ea5d 100644 --- a/src/main/java/com/back/domain/user/dto/RefreshTokenResDto.java +++ b/src/main/java/com/back/domain/user/dto/RefreshTokenResDto.java @@ -16,6 +16,5 @@ public static class UserInfoDto { private final String nickname; private final Boolean isFirstLogin; private final Double abvDegree; - } } From 4c7a04edfd1e7faa49cb886711541b7a5fa66223 Mon Sep 17 00:00:00 2001 From: seungwookc97 Date: Mon, 13 Oct 2025 10:56:32 +0900 Subject: [PATCH 2/4] =?UTF-8?q?refactor=20:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=8B=9C=20=EC=B6=94=EA=B0=80=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/user/service/UserAuthService.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/back/domain/user/service/UserAuthService.java b/src/main/java/com/back/domain/user/service/UserAuthService.java index a443a1ac..ce5ef57e 100644 --- a/src/main/java/com/back/domain/user/service/UserAuthService.java +++ b/src/main/java/com/back/domain/user/service/UserAuthService.java @@ -22,6 +22,8 @@ import java.util.Optional; import java.util.Set; +import static org.springframework.security.core.context.SecurityContextHolder.*; + @Slf4j @Service @RequiredArgsConstructor @@ -199,14 +201,30 @@ public RefreshTokenResDto refreshTokens(HttpServletRequest request, HttpServletR //토큰 끊기면서 OAuth 자동 로그아웃 public void logout(HttpServletRequest request, HttpServletResponse response) { + // 1. RefreshToken DB에서 삭제 String refreshToken = jwtUtil.getRefreshTokenFromCookie(request); - if (refreshToken != null) { refreshTokenService.revokeToken(refreshToken); } + // 2. JWT 쿠키 삭제 jwtUtil.removeAccessTokenCookie(response); jwtUtil.removeRefreshTokenCookie(response); + + // 3. Spring Security 세션 무효화 (Redis 포함) + try { + if (request.getSession(false) != null) { + request.getSession().invalidate(); + log.debug("세션 무효화"); + } + } catch (IllegalStateException e) { + log.debug("세션이 이미 무효화되어 있음"); + } + + // 4. SecurityContext 클리어 + clearContext(); + + log.info("로그아웃 완료 - JWT, 세션, SecurityContext 모두 정리됨"); } @Transactional From e1a48420c5f38f066b674794839d447f5a87aef8 Mon Sep 17 00:00:00 2001 From: seungwookc97 Date: Mon, 13 Oct 2025 15:44:00 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C.=20=EB=A7=8C=EB=A3=8C=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=20=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a0594f1b..e0dd08b1 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -99,11 +99,10 @@ custom: jwt: secretKey: ${JWT_SECRET_KEY} accessToken: - expirationSeconds: "#{60}" # 15분 곱하기 + expirationSeconds: "#{60*15}" refreshToken: expirationSeconds: "#{60*60*24*30}" - idleTimeoutHours: "#{1}" -# "#{60*6*4}" + idleTimeoutHours: "#{60*6*4}" management: From 899439509b92804c574e8cade00446f2cb2bf45d Mon Sep 17 00:00:00 2001 From: seungwookc97 Date: Tue, 14 Oct 2025 15:08:21 +0900 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=EC=9C=A0=EC=A0=80=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20api=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserAuthController.java | 4 +--- .../domain/user/service/UserAuthService.java | 20 +++++++++++++------ .../back/global/security/SecurityConfig.java | 1 + 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/back/domain/user/controller/UserAuthController.java b/src/main/java/com/back/domain/user/controller/UserAuthController.java index ae273914..ff113192 100644 --- a/src/main/java/com/back/domain/user/controller/UserAuthController.java +++ b/src/main/java/com/back/domain/user/controller/UserAuthController.java @@ -55,9 +55,7 @@ public RsData logout(HttpServletRequest request, HttpServletResponse respo @Operation(summary = "현재 로그인한 유저 정보 조회", description = "세션 유효성 검증 및 사용자 정보 반환") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "인증된 유저 정보 반환 성공"), - @ApiResponse(responseCode = "401", description = "인증되지 않은 사용자"), - @ApiResponse(responseCode = "500", description = "서버 내부 오류") + @ApiResponse(responseCode = "200", description = "사용자 정보 조회"), }) @GetMapping("/me") public RsData getCurrentUser() { diff --git a/src/main/java/com/back/domain/user/service/UserAuthService.java b/src/main/java/com/back/domain/user/service/UserAuthService.java index ce5ef57e..8dfed051 100644 --- a/src/main/java/com/back/domain/user/service/UserAuthService.java +++ b/src/main/java/com/back/domain/user/service/UserAuthService.java @@ -234,21 +234,28 @@ public void setFirstLoginFalse(Long id) { } // 현재 로그인한 사용자 정보 조회 (세션 검증용) + // 변경: 항상 200 응답, 비로그인 시 user: null 반환 public UserMeResDto getCurrentUser() { try { User actor = rq.getActor(); + // 비로그인 상태: user null 반환 if (actor == null) { - log.debug("인증되지 않은 사용자"); - throw new ServiceException(401, "인증되지 않은 사용자"); + log.debug("인증되지 않은 사용자 - user: null 반환"); + return UserMeResDto.builder() + .user(null) + .build(); } Optional userOpt = userRepository.findById(actor.getId()); if (userOpt.isEmpty()) { log.warn("사용자 ID {}를 DB에서 찾을 수 없음 (토큰은 유효하나 사용자 삭제됨)", actor.getId()); - throw new ServiceException(401, "인증되지 않은 사용자"); + return UserMeResDto.builder() + .user(null) + .build(); } + // 로그인 상태: user 정보 반환 User user = userOpt.get(); String provider = extractProvider(user.getOauthId()); @@ -263,11 +270,12 @@ public UserMeResDto getCurrentUser() { .build()) .build(); - } catch (ServiceException e) { - throw e; } catch (Exception e) { log.error("사용자 정보 조회 중 서버 오류 발생: {}", e.getMessage(), e); - throw new ServiceException(500, "서버 내부 오류"); + // 예외 발생 시에도 user: null 반환 + return UserMeResDto.builder() + .user(null) + .build(); } } diff --git a/src/main/java/com/back/global/security/SecurityConfig.java b/src/main/java/com/back/global/security/SecurityConfig.java index 4ca3cef4..f6491dd8 100644 --- a/src/main/java/com/back/global/security/SecurityConfig.java +++ b/src/main/java/com/back/global/security/SecurityConfig.java @@ -69,6 +69,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/login/oauth2/**").permitAll() .requestMatchers("/swagger-ui/**", "/api-docs/**").permitAll() .requestMatchers("/user/auth/refresh").permitAll() + .requestMatchers("/user/auth/me").permitAll() // 권한 불필요 - 조회 API .requestMatchers(GET, "/cocktails/**").permitAll()