From 8aa96d5fbdc526f47bb248d4eae373d5cf6e0289 Mon Sep 17 00:00:00 2001 From: sohot8653 Date: Wed, 20 Aug 2025 16:30:46 +0900 Subject: [PATCH] =?UTF-8?q?[JWT=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EC=84=A0]?= =?UTF-8?q?=20Refresh=20Token=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EA=B0=B1?= =?UTF-8?q?=EC=8B=A0=20=EB=A1=9C=EC=A7=81=EC=9D=84=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=ED=99=94=ED=95=98=EC=97=AC=20JwtUtils=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EC=97=90=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80.=20JwtTokenIssuanceFilter=EC=99=80=20JwtTokenValidati?= =?UTF-8?q?onFilter=EC=97=90=EC=84=9C=20=EC=83=88=EB=A1=9C=EC=9A=B4=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=82=AC=EC=9A=A9=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=BD=94=EB=93=9C=20=EA=B0=84=EA=B2=B0=ED=99=94=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9C=A0=EC=A7=80=EB=B3=B4=EC=88=98=EC=84=B1=20?= =?UTF-8?q?=ED=96=A5=EC=83=81.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/JwtTokenIssuanceFilter.java | 20 ++-------- .../security/JwtTokenValidationFilter.java | 4 ++ .../bio_backend/global/utils/JwtUtils.java | 39 +++++++++++++++++++ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/bio/bio_backend/global/security/JwtTokenIssuanceFilter.java b/src/main/java/com/bio/bio_backend/global/security/JwtTokenIssuanceFilter.java index 9585b3b..1ca97a4 100644 --- a/src/main/java/com/bio/bio_backend/global/security/JwtTokenIssuanceFilter.java +++ b/src/main/java/com/bio/bio_backend/global/security/JwtTokenIssuanceFilter.java @@ -3,7 +3,6 @@ package com.bio.bio_backend.global.security; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import com.bio.bio_backend.global.dto.ApiResponseDto; @@ -76,29 +75,18 @@ public class JwtTokenIssuanceFilter extends UsernamePasswordAuthenticationFilter String accessToken = jwtUtils.generateToken(member.getUserId(), member.getRole().getValue(), Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_access")))); - String refreshToken = jwtUtils.generateToken(member.getUserId(), member.getRole().getValue(), - Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_refresh")))); + // 모듈화된 메서드 사용 + String refreshToken = jwtUtils.createAndSaveRefreshToken(member.getUserId(), member.getRole().getValue()); member.setRefreshToken(refreshToken); member.setLastLoginAt(LocalDateTime.now()); - memberService.updateRefreshToken(member); - - // Refresh 토큰 쿠키 저장 - Cookie refreshTokenCookie = new Cookie("RefreshToken", refreshToken); - refreshTokenCookie.setHttpOnly(true); - refreshTokenCookie.setSecure(false); - refreshTokenCookie.setPath("/"); - refreshTokenCookie.setMaxAge(Integer.parseInt(env.getProperty("token.expiration_time_refresh"))); + // Refresh 토큰 쿠키 저장 - 모듈화된 메서드 사용 + jwtUtils.setRefreshTokenCookie(response, refreshToken); // JWT 토큰 전달 response.setHeader("Authorization", "Bearer " + accessToken); - response.addHeader("Set-Cookie", - String.format("%s=%s; HttpOnly; Secure; Path=/; Max-Age=%d; SameSite=None", - refreshTokenCookie.getName(), - refreshTokenCookie.getValue(), - refreshTokenCookie.getMaxAge())); SecurityContextHolderStrategy contextHolder = SecurityContextHolder.getContextHolderStrategy(); SecurityContext context = contextHolder.createEmptyContext(); diff --git a/src/main/java/com/bio/bio_backend/global/security/JwtTokenValidationFilter.java b/src/main/java/com/bio/bio_backend/global/security/JwtTokenValidationFilter.java index 76f86a7..9464e1f 100644 --- a/src/main/java/com/bio/bio_backend/global/security/JwtTokenValidationFilter.java +++ b/src/main/java/com/bio/bio_backend/global/security/JwtTokenValidationFilter.java @@ -73,6 +73,10 @@ public class JwtTokenValidationFilter extends OncePerRequestFilter { // 새로운 Access Token을 응답 헤더에 설정 response.setHeader("Authorization", "Bearer " + newAccessToken); + // Refresh Token 갱신 + String newRefreshToken = jwtUtils.refreshTokens(username, role); + jwtUtils.setRefreshTokenCookie(response, newRefreshToken); + // 인증 정보 설정 UserDetails userDetails = memberService.loadUserByUsername(username); if (userDetails != null) { diff --git a/src/main/java/com/bio/bio_backend/global/utils/JwtUtils.java b/src/main/java/com/bio/bio_backend/global/utils/JwtUtils.java index cec8caa..c8f7897 100644 --- a/src/main/java/com/bio/bio_backend/global/utils/JwtUtils.java +++ b/src/main/java/com/bio/bio_backend/global/utils/JwtUtils.java @@ -6,15 +6,19 @@ import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import com.bio.bio_backend.domain.base.member.service.MemberService; +import com.bio.bio_backend.domain.base.member.dto.MemberDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.crypto.SecretKey; import java.util.Date; +import java.util.Objects; @Component @RequiredArgsConstructor @@ -22,6 +26,7 @@ import java.util.Date; public class JwtUtils { private final MemberService memberService; + private final Environment env; @Value("${token.secret_key}") private String SECRET_KEY; @@ -87,4 +92,38 @@ public class JwtUtils { } return null; } + + // Refresh Token 생성 및 DB 저장 + public String createAndSaveRefreshToken(String username, String role) { + String refreshToken = generateToken(username, role, + Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_refresh")))); + + // MemberDto 객체 생성하여 updateRefreshToken 호출 + MemberDto member = new MemberDto(); + member.setUserId(username); + member.setRefreshToken(refreshToken); + memberService.updateRefreshToken(member); + + return refreshToken; + } + + // Refresh Token 갱신 (Access Token 갱신 시 함께) + public String refreshTokens(String username, String role) { + // 새로운 Refresh Token 생성 및 DB 저장 + String newRefreshToken = createAndSaveRefreshToken(username, role); + + log.info("Refresh Token 갱신 완료: {}", username); + return newRefreshToken; + } + + // Refresh Token 쿠키 설정 + public void setRefreshTokenCookie(HttpServletResponse response, String refreshToken) { + Cookie refreshTokenCookie = new Cookie("RefreshToken", refreshToken); + refreshTokenCookie.setHttpOnly(true); + refreshTokenCookie.setSecure(false); + refreshTokenCookie.setPath("/"); + refreshTokenCookie.setMaxAge(Integer.parseInt(env.getProperty("token.expiration_time_refresh"))); + + response.addCookie(refreshTokenCookie); + } }