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 ae27391..ff11319 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/dto/RefreshTokenResDto.java b/src/main/java/com/back/domain/user/dto/RefreshTokenResDto.java index 3e70594..5131ea5 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; - } } 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 a443a1a..8dfed05 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 @@ -216,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()); @@ -245,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 4ca3cef..f6491dd 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() diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ab1d68a..e99a67c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -102,11 +102,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: