diff --git a/src/main/java/Mua/Mua_backend/global/config/SecurityConfig.java b/src/main/java/Mua/Mua_backend/global/config/SecurityConfig.java index ab9faab..4be2001 100644 --- a/src/main/java/Mua/Mua_backend/global/config/SecurityConfig.java +++ b/src/main/java/Mua/Mua_backend/global/config/SecurityConfig.java @@ -47,6 +47,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti ) .authorizeHttpRequests(auth -> auth .requestMatchers("/", "/login/**", "/oauth2/**", "/login/oauth2/**", + "/token/refresh", "/token/logout", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", "/h2-console/**", "/api/feeds/**", "/api/notifications/**", "/api/members/**", "/health").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") diff --git a/src/main/java/Mua/Mua_backend/global/security/jwt/JwtLoginAPIController.java b/src/main/java/Mua/Mua_backend/global/security/jwt/JwtLoginAPIController.java index c83a540..e01acff 100644 --- a/src/main/java/Mua/Mua_backend/global/security/jwt/JwtLoginAPIController.java +++ b/src/main/java/Mua/Mua_backend/global/security/jwt/JwtLoginAPIController.java @@ -9,29 +9,45 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; +import java.util.Arrays; @RestController @RequestMapping("/token") @RequiredArgsConstructor @Transactional +@Slf4j public class JwtLoginAPIController { private final JwtTokenUtil jwtTokenUtil; private final RefreshTokenRepository refreshTokenRepository; + @Value("${app.cookie.secure:true}") + private boolean cookieSecure; + + @Value("${app.cookie.same-site:None}") + private String cookieSameSite; + @PostMapping("/refresh") public ResponseEntity refresh(HttpServletRequest request, HttpServletResponse response) { + log.info("POST /token/refresh sessionId={}, requestedSessionId={}, cookies={}", + request.getSession(false) != null ? request.getSession(false).getId() : null, + request.getRequestedSessionId(), + request.getCookies() == null ? "[]" : Arrays.stream(request.getCookies()) + .map(Cookie::getName) + .toList()); String refreshToken = null; @@ -73,13 +89,15 @@ public ResponseEntity refresh(HttpServletRequest request, refreshTokenRepository.save(storedToken); // 새 RefreshToken 쿠키 다시 내려줌 - Cookie newCookie = new Cookie("refreshToken", newRefreshToken); - newCookie.setHttpOnly(true); - newCookie.setSecure(false); - newCookie.setPath("/"); - newCookie.setMaxAge(60 * 60 * 24 * 14); + ResponseCookie newCookie = ResponseCookie.from("refreshToken", newRefreshToken) + .httpOnly(true) + .secure(cookieSecure) + .sameSite(cookieSameSite) + .path("/") + .maxAge(60 * 60 * 24 * 14) + .build(); - response.addCookie(newCookie); + response.addHeader(HttpHeaders.SET_COOKIE, newCookie.toString()); return ResponseEntity.ok() .header(HttpHeaders.AUTHORIZATION, "Bearer " + newAccessToken) @@ -118,10 +136,14 @@ public ResponseEntity logout( refreshTokenRepository.deleteByToken(refreshToken); // 쿠키 삭제 - Cookie deleteCookie = new Cookie("refreshToken", null); - deleteCookie.setMaxAge(0); - deleteCookie.setPath("/"); - response.addCookie(deleteCookie); + ResponseCookie deleteCookie = ResponseCookie.from("refreshToken", "") + .httpOnly(true) + .secure(cookieSecure) + .sameSite(cookieSameSite) + .path("/") + .maxAge(0) + .build(); + response.addHeader(HttpHeaders.SET_COOKIE, deleteCookie.toString()); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/Mua/Mua_backend/global/security/oauth/OAuth2LoginSuccessHandler.java b/src/main/java/Mua/Mua_backend/global/security/oauth/OAuth2LoginSuccessHandler.java index 71f2b6c..de53a1b 100644 --- a/src/main/java/Mua/Mua_backend/global/security/oauth/OAuth2LoginSuccessHandler.java +++ b/src/main/java/Mua/Mua_backend/global/security/oauth/OAuth2LoginSuccessHandler.java @@ -29,6 +29,12 @@ public class OAuth2LoginSuccessHandler implements AuthenticationSuccessHandler { @Value("${app.oauth.redirect-uri}") private String redirectUri; + @Value("${app.cookie.secure:true}") + private boolean cookieSecure; + + @Value("${app.cookie.same-site:None}") + private String cookieSameSite; + @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { @@ -55,8 +61,8 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo ResponseCookie refreshCookie = ResponseCookie.from("refreshToken", refreshToken) .httpOnly(true) - .secure(true) // 로컬 테스트면 false, HTTPS면 true - .sameSite("None") + .secure(cookieSecure) + .sameSite(cookieSameSite) .path("/") .maxAge(60 * 60 * 24 * 14) .build();