From d34abc37d553dcde96667f2361fc86c13416d6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Tue, 14 Jan 2025 17:43:11 +0900 Subject: [PATCH 01/11] =?UTF-8?q?:recycle:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=EC=96=91=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mycom/socket/auth/service/MailService.java | 12 +++++------- .../mycom/socket/global/service/RedisService.java | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/mycom/socket/auth/service/MailService.java b/src/main/java/com/mycom/socket/auth/service/MailService.java index 18bfda4..5203ac6 100644 --- a/src/main/java/com/mycom/socket/auth/service/MailService.java +++ b/src/main/java/com/mycom/socket/auth/service/MailService.java @@ -90,15 +90,13 @@ public EmailVerificationResponse verifyCode(String email, String code) { throw new BaseException("유효하지 않은 인증 코드 형식입니다.", HttpStatus.BAD_REQUEST); } - try { - String saveCode = redisService.getCode(code); // 인증코드 검증 - if(!saveCode.equals(code)) { - throw new BaseException("인증 코드가 일치하지 않습니다.", HttpStatus.BAD_REQUEST); - } - return EmailVerificationResponse.of("이메일 인증이 완료되었습니다."); - } catch (Exception e) { + String savedCode = redisService.getCode(email); // Redis에서 코드를 가져옴 + + if(!savedCode.equals(code)){ throw new BaseException("인증 코드가 일치하지 않습니다.", HttpStatus.BAD_REQUEST); } + redisService.saveVerifiedEmail(email); + return EmailVerificationResponse.of("이메일 인증이 완료되었습니다."); } } diff --git a/src/main/java/com/mycom/socket/global/service/RedisService.java b/src/main/java/com/mycom/socket/global/service/RedisService.java index 09e8f9e..104f34c 100644 --- a/src/main/java/com/mycom/socket/global/service/RedisService.java +++ b/src/main/java/com/mycom/socket/global/service/RedisService.java @@ -90,7 +90,7 @@ public void saveVerifiedEmail(String email) { */ public boolean isEmailVerified(String email) { Object verified = redisTemplate.opsForValue().get(VERIFIED_EMAIL_PREFIX + email); - return "true".equals(verified); + return verified != null && "true".equals(verified.toString()); } } From 49b9c5f06c16dab9849f067d3842ca65cf0ea7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Tue, 14 Jan 2025 17:44:06 +0900 Subject: [PATCH 02/11] =?UTF-8?q?:recycle:=20JWT=20Refresh=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../socket/auth/config/JWTProperties.java | 6 +- .../auth/controller/RefreshController.java | 60 +++++++++++++++++++ .../auth/dto/response/TokenResponse.java | 9 +++ .../com/mycom/socket/auth/jwt/JWTFilter.java | 2 +- .../com/mycom/socket/auth/jwt/JWTUtil.java | 19 +++++- .../socket/auth/security/CookieUtil.java | 29 ++++++++- .../socket/auth/security/LoginFilter.java | 9 ++- .../socket/auth/service/AuthService.java | 16 ++++- .../socket/member/service/LoginTest.java | 9 ++- 9 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/mycom/socket/auth/controller/RefreshController.java create mode 100644 src/main/java/com/mycom/socket/auth/dto/response/TokenResponse.java diff --git a/src/main/java/com/mycom/socket/auth/config/JWTProperties.java b/src/main/java/com/mycom/socket/auth/config/JWTProperties.java index f35a579..ac6a1e3 100644 --- a/src/main/java/com/mycom/socket/auth/config/JWTProperties.java +++ b/src/main/java/com/mycom/socket/auth/config/JWTProperties.java @@ -10,8 +10,10 @@ @ConfigurationProperties(prefix = "jwt") public class JWTProperties { private String secret; - private long accessTokenValidityInSeconds = 1800; - private String cookieName = "Authorization"; + private long accessTokenValidityInSeconds; + private long refreshTokenValidityInSeconds; + private String accessTokenCookieName; + private String refreshTokenCookieName; private String issuer = "go_socket"; private boolean secureCookie = false; } diff --git a/src/main/java/com/mycom/socket/auth/controller/RefreshController.java b/src/main/java/com/mycom/socket/auth/controller/RefreshController.java new file mode 100644 index 0000000..8fec157 --- /dev/null +++ b/src/main/java/com/mycom/socket/auth/controller/RefreshController.java @@ -0,0 +1,60 @@ +package com.mycom.socket.auth.controller; + +import com.mycom.socket.auth.config.JWTProperties; +import com.mycom.socket.auth.dto.response.TokenResponse; +import com.mycom.socket.auth.jwt.JWTUtil; +import com.mycom.socket.auth.security.CookieUtil; +import com.mycom.socket.global.exception.BadRequestException; +import io.jsonwebtoken.JwtException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class RefreshController { + + private final JWTUtil jwtUtil; + private final CookieUtil cookieUtil; + private final JWTProperties jwtProperties; + + @PostMapping("/refresh") + public TokenResponse refreshAccessToken(HttpServletRequest request, HttpServletResponse response) { + String refreshToken = extractRefreshToken(request); + + try { + jwtUtil.validateToken(refreshToken); + } catch (JwtException e) { + response.addCookie(cookieUtil.createExpiredRefreshCookie()); + throw new BadRequestException("유효하지 않은 리프레시 토큰입니다. 다시 로그인해주세요."); + } + + String email = jwtUtil.getEmail(refreshToken); + String newAccessToken = jwtUtil.createToken(email, jwtProperties.getAccessTokenValidityInSeconds()); + + Cookie accessTokenCookie = cookieUtil.createAuthCookie(newAccessToken); + response.addCookie(accessTokenCookie); + + String newRefreshToken = jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds()); + Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(newRefreshToken); + response.addCookie(refreshTokenCookie); + + return TokenResponse.of(newAccessToken); + } + + private String extractRefreshToken(HttpServletRequest request) { + if (request.getCookies() == null) { + throw new BadRequestException("리프레시 토큰이 없습니다. 다시 로그인해주세요."); + } + + for (Cookie cookie : request.getCookies()) { + if (jwtProperties.getRefreshTokenCookieName().equals(cookie.getName())) { + return cookie.getValue(); + } + } + throw new BadRequestException("리프레시 토큰이 없습니다. 다시 로그인해주세요."); + } +} \ No newline at end of file diff --git a/src/main/java/com/mycom/socket/auth/dto/response/TokenResponse.java b/src/main/java/com/mycom/socket/auth/dto/response/TokenResponse.java new file mode 100644 index 0000000..5d27daa --- /dev/null +++ b/src/main/java/com/mycom/socket/auth/dto/response/TokenResponse.java @@ -0,0 +1,9 @@ +package com.mycom.socket.auth.dto.response; + +public record TokenResponse( + String accessToken +) { + public static TokenResponse of(String accessToken) { + return new TokenResponse(accessToken); + } +} diff --git a/src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java b/src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java index 97f27d9..dca4486 100644 --- a/src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java +++ b/src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java @@ -46,7 +46,7 @@ private String resolveTokenFromCookie(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { - if (jwtProperties.getCookieName().equals(cookie.getName())) { + if (jwtProperties.getAccessTokenCookieName().equals(cookie.getName())) { return cookie.getValue(); } } diff --git a/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java b/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java index a8b963b..b4dfc4a 100644 --- a/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java +++ b/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java @@ -25,13 +25,26 @@ public JWTUtil(JWTProperties jwtProperties) { ); } + /** + * 액세스 토큰 생성 + */ + public String createAccessToken(String email) { + return createToken(email, jwtProperties.getAccessTokenValidityInSeconds()); + } + + /** + * 리프레시 토큰 생성 + */ + public String createRefreshToken(String email) { + return createToken(email, jwtProperties.getRefreshTokenValidityInSeconds()); + } + /** * JWT 토큰 생성 */ - public String createToken(String email) { + public String createToken(String email, long validityInSeconds) { Date now = new Date(); - Date validity = new Date(now.getTime() + - (jwtProperties.getAccessTokenValidityInSeconds() * 1000)); + Date validity = new Date(now.getTime() + (validityInSeconds * 1000)); return Jwts.builder() .issuer(jwtProperties.getIssuer()) diff --git a/src/main/java/com/mycom/socket/auth/security/CookieUtil.java b/src/main/java/com/mycom/socket/auth/security/CookieUtil.java index 1826b31..8accc68 100644 --- a/src/main/java/com/mycom/socket/auth/security/CookieUtil.java +++ b/src/main/java/com/mycom/socket/auth/security/CookieUtil.java @@ -14,7 +14,7 @@ public class CookieUtil { * 인증 쿠키 생성 */ public Cookie createAuthCookie(String token) { - Cookie cookie = new Cookie(jwtProperties.getCookieName(), token); + Cookie cookie = new Cookie(jwtProperties.getAccessTokenCookieName(), token); cookie.setHttpOnly(true); cookie.setSecure(jwtProperties.isSecureCookie()); cookie.setPath("/"); @@ -22,11 +22,36 @@ public Cookie createAuthCookie(String token) { return cookie; } + /** + * 리프레시 토큰 쿠키 생성 + */ + public Cookie createRefreshCookie(String token) { + Cookie cookie = new Cookie(jwtProperties.getRefreshTokenCookieName(), token); + cookie.setHttpOnly(true); + cookie.setSecure(jwtProperties.isSecureCookie()); + cookie.setPath("/"); + cookie.setMaxAge((int) jwtProperties.getRefreshTokenValidityInSeconds()); + return cookie; + } + + /** * 인증 쿠키 만료 처리 */ public Cookie createExpiredAuthCookie() { - Cookie cookie = new Cookie(jwtProperties.getCookieName(), null); + Cookie cookie = new Cookie(jwtProperties.getAccessTokenCookieName(), null); + cookie.setHttpOnly(true); + cookie.setSecure(true); + cookie.setPath("/"); + cookie.setMaxAge(0); // 즉시 만료 + return cookie; + } + + /** + * 리프레시 토큰 쿠키 만료 처리 + */ + public Cookie createExpiredRefreshCookie() { + Cookie cookie = new Cookie(jwtProperties.getRefreshTokenCookieName(), null); cookie.setHttpOnly(true); cookie.setSecure(true); cookie.setPath("/"); diff --git a/src/main/java/com/mycom/socket/auth/security/LoginFilter.java b/src/main/java/com/mycom/socket/auth/security/LoginFilter.java index 5c27f35..7ce4aad 100644 --- a/src/main/java/com/mycom/socket/auth/security/LoginFilter.java +++ b/src/main/java/com/mycom/socket/auth/security/LoginFilter.java @@ -51,11 +51,14 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR MemberDetails memberDetails = (MemberDetails) authResult.getPrincipal(); Member member = memberDetails.getMember(); - String token = jwtUtil.createToken(member.getEmail()); + String accessToken = jwtUtil.createAccessToken(member.getEmail()); //액세스 토큰 생성 + String refreshToken = jwtUtil.createRefreshToken(member.getEmail()); //리프레시 토큰 생성 // 쿠키 생성 및 설정 - Cookie authCookie = cookieUtil.createAuthCookie(token); - response.addCookie(authCookie); + Cookie accessTokenCookie = cookieUtil.createAuthCookie(accessToken); //액세스 토큰 쿠키 + Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(refreshToken); //리프레시 토큰 쿠키 + response.addCookie(accessTokenCookie); + response.addCookie(refreshTokenCookie); // 로그인 응답 생성 LoginResponse loginResponse = new LoginResponse(member.getEmail(), member.getNickname()); diff --git a/src/main/java/com/mycom/socket/auth/service/AuthService.java b/src/main/java/com/mycom/socket/auth/service/AuthService.java index 66e97ef..a8c8f4f 100644 --- a/src/main/java/com/mycom/socket/auth/service/AuthService.java +++ b/src/main/java/com/mycom/socket/auth/service/AuthService.java @@ -1,5 +1,6 @@ package com.mycom.socket.auth.service; +import com.mycom.socket.auth.config.JWTProperties; import com.mycom.socket.auth.dto.response.RegisterResponse; import com.mycom.socket.auth.jwt.JWTUtil; import com.mycom.socket.auth.security.CookieUtil; @@ -28,6 +29,7 @@ public class AuthService { private final JWTUtil jwtUtil; private final MailService mailService; private final CookieUtil cookieUtil; + private final JWTProperties jwtProperties; /** * 사용자 로그인 처리 @@ -46,8 +48,17 @@ public LoginResponse login(LoginRequest request, HttpServletResponse response) { throw new BadRequestException("잘못된 비밀번호입니다."); } - String token = jwtUtil.createToken(member.getEmail()); - response.addCookie(cookieUtil.createAuthCookie(token)); // CookieUtil 사용 + String refreshToken = jwtUtil.createToken(member.getEmail(), + jwtProperties.getRefreshTokenValidityInSeconds()); + + Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(refreshToken); + response.addCookie(refreshTokenCookie); + + String accessToken = jwtUtil.createToken(member.getEmail(), + jwtProperties.getAccessTokenValidityInSeconds()); + + Cookie accessTokenCookie = cookieUtil.createAuthCookie(accessToken); + response.addCookie(accessTokenCookie); return LoginResponse.of(member.getEmail(), member.getNickname()); } @@ -101,5 +112,6 @@ public RegisterResponse register(RegisterRequest request) { */ public void logout(HttpServletResponse response) { response.addCookie(cookieUtil.createExpiredAuthCookie()); // CookieUtil 사용 + response.addCookie(cookieUtil.createExpiredRefreshCookie()); } } diff --git a/src/test/java/com/mycom/socket/member/service/LoginTest.java b/src/test/java/com/mycom/socket/member/service/LoginTest.java index bd07eb9..8019f64 100644 --- a/src/test/java/com/mycom/socket/member/service/LoginTest.java +++ b/src/test/java/com/mycom/socket/member/service/LoginTest.java @@ -1,5 +1,6 @@ package com.mycom.socket.member.service; +import com.mycom.socket.auth.config.JWTProperties; import com.mycom.socket.auth.dto.request.LoginRequest; import com.mycom.socket.auth.dto.response.LoginResponse; import com.mycom.socket.auth.jwt.JWTUtil; @@ -13,7 +14,6 @@ import jakarta.servlet.http.HttpServletResponse; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -36,6 +36,9 @@ class LoginTest { @Mock private PasswordEncoder passwordEncoder; + @Mock + private JWTProperties jwtProperties; + @Mock private JWTUtil jwtUtil; @@ -70,7 +73,7 @@ class LoginTest { when(memberRepository.findByEmail(email)).thenReturn(Optional.of(member)); when(passwordEncoder.matches(password, encodedPassword)).thenReturn(true); - when(jwtUtil.createToken(email)).thenReturn(token); + when(jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds())).thenReturn(token); when(cookieUtil.createAuthCookie(token)).thenReturn(authCookie); // CookieUtil 동작 정의 // when @@ -82,7 +85,7 @@ class LoginTest { assertEquals(nickname, response.nickname()); verify(memberRepository).findByEmail(email); verify(passwordEncoder).matches(password, encodedPassword); - verify(jwtUtil).createToken(email); + verify(jwtUtil).createToken(email, jwtProperties.getRefreshTokenValidityInSeconds()); verify(cookieUtil).createAuthCookie(token); } From 7341b5b457ad965fbb54a3db815b1562fff873a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Tue, 14 Jan 2025 20:27:21 +0900 Subject: [PATCH 03/11] =?UTF-8?q?:recycle:=20=EC=BF=A0=ED=82=A4=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../socket/auth/security/CookieUtil.java | 73 +++++++++++-------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/mycom/socket/auth/security/CookieUtil.java b/src/main/java/com/mycom/socket/auth/security/CookieUtil.java index 8accc68..ace18a4 100644 --- a/src/main/java/com/mycom/socket/auth/security/CookieUtil.java +++ b/src/main/java/com/mycom/socket/auth/security/CookieUtil.java @@ -11,51 +11,64 @@ public class CookieUtil { private final JWTProperties jwtProperties; /** - * 인증 쿠키 생성 + * 공통 쿠키 생성 메소드 + * 모든 종류의 쿠키 생성에 사용되는 기본 메소드입니다. + * + * @param name 쿠키의 이름 + * @param value 쿠키에 저장될 값 (토큰) + * @param maxAge 쿠키의 유효 시간 (초 단위) + * @param secure HTTPS 프로토콜에서만 전송 여부 + * @return 생성된 쿠키 객체 */ - public Cookie createAuthCookie(String token) { - Cookie cookie = new Cookie(jwtProperties.getAccessTokenCookieName(), token); + private Cookie createCookie(String name, String value, long maxAge, boolean secure) { + Cookie cookie = new Cookie(name, value); cookie.setHttpOnly(true); - cookie.setSecure(jwtProperties.isSecureCookie()); + cookie.setSecure(secure); cookie.setPath("/"); - cookie.setMaxAge((int) jwtProperties.getAccessTokenValidityInSeconds()); + cookie.setMaxAge((int) maxAge); return cookie; } /** - * 리프레시 토큰 쿠키 생성 + * Access Token을 저장하는 쿠키 생성 + * 클라이언트 인증에 사용되는 Access Token을 쿠키에 저장합니다. + * + * @param token JWT Access Token 문자열 + * @return Access Token이 저장된 쿠키 */ - public Cookie createRefreshCookie(String token) { - Cookie cookie = new Cookie(jwtProperties.getRefreshTokenCookieName(), token); - cookie.setHttpOnly(true); - cookie.setSecure(jwtProperties.isSecureCookie()); - cookie.setPath("/"); - cookie.setMaxAge((int) jwtProperties.getRefreshTokenValidityInSeconds()); - return cookie; + public Cookie createAuthCookie(String token) { + return createCookie( + jwtProperties.getAccessTokenCookieName(), + token, + jwtProperties.getAccessTokenValidityInSeconds(), + jwtProperties.isSecureCookie() + ); } - /** - * 인증 쿠키 만료 처리 + * Refresh Token을 저장하는 쿠키 생성 + * Access Token 재발급에 사용되는 Refresh Token을 쿠키에 저장합니다. + * + * @param token JWT Refresh Token 문자열 + * @return Refresh Token이 저장된 쿠키 */ - public Cookie createExpiredAuthCookie() { - Cookie cookie = new Cookie(jwtProperties.getAccessTokenCookieName(), null); - cookie.setHttpOnly(true); - cookie.setSecure(true); - cookie.setPath("/"); - cookie.setMaxAge(0); // 즉시 만료 - return cookie; + public Cookie createRefreshCookie(String token) { + return createCookie( + jwtProperties.getRefreshTokenCookieName(), + token, + jwtProperties.getRefreshTokenValidityInSeconds(), + jwtProperties.isSecureCookie() + ); } /** - * 리프레시 토큰 쿠키 만료 처리 + * 만료된 쿠키 생성 + * 로그아웃 또는 토큰 무효화 시 기존 쿠키를 만료시키기 위해 사용됩니다. + * + * @param name 만료시킬 쿠키의 이름 + * @return 즉시 만료되도록 설정된 쿠키 */ - public Cookie createExpiredRefreshCookie() { - Cookie cookie = new Cookie(jwtProperties.getRefreshTokenCookieName(), null); - cookie.setHttpOnly(true); - cookie.setSecure(true); - cookie.setPath("/"); - cookie.setMaxAge(0); // 즉시 만료 - return cookie; + public Cookie createExpiredCookie(String name) { + return createCookie(name, null, 0, true); } } From 2a4d71e60a13987bf8265c60be93d916ea97c6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Tue, 14 Jan 2025 20:27:30 +0900 Subject: [PATCH 04/11] =?UTF-8?q?:recycle:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/RefreshController.java | 47 ++++----- .../com/mycom/socket/auth/jwt/JWTUtil.java | 98 ++++++++++++++----- 2 files changed, 98 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/mycom/socket/auth/controller/RefreshController.java b/src/main/java/com/mycom/socket/auth/controller/RefreshController.java index 8fec157..edb2c28 100644 --- a/src/main/java/com/mycom/socket/auth/controller/RefreshController.java +++ b/src/main/java/com/mycom/socket/auth/controller/RefreshController.java @@ -13,6 +13,9 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Arrays; +import java.util.Optional; + @RestController @RequiredArgsConstructor public class RefreshController { @@ -23,38 +26,36 @@ public class RefreshController { @PostMapping("/refresh") public TokenResponse refreshAccessToken(HttpServletRequest request, HttpServletResponse response) { - String refreshToken = extractRefreshToken(request); + String refreshToken = extractRefreshToken(request) + .orElseThrow(() -> new BadRequestException("리프레시 토큰이 없습니다. 다시 로그인해주세요.")); try { - jwtUtil.validateToken(refreshToken); - } catch (JwtException e) { - response.addCookie(cookieUtil.createExpiredRefreshCookie()); - throw new BadRequestException("유효하지 않은 리프레시 토큰입니다. 다시 로그인해주세요."); - } - - String email = jwtUtil.getEmail(refreshToken); - String newAccessToken = jwtUtil.createToken(email, jwtProperties.getAccessTokenValidityInSeconds()); + if (!jwtUtil.validateToken(refreshToken)) { + throw new JwtException("Invalid refresh token"); + } - Cookie accessTokenCookie = cookieUtil.createAuthCookie(newAccessToken); - response.addCookie(accessTokenCookie); + String email = jwtUtil.getEmail(refreshToken); + String newAccessToken = jwtUtil.createToken(email, jwtProperties.getAccessTokenValidityInSeconds()); + String newRefreshToken = jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds()); - String newRefreshToken = jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds()); - Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(newRefreshToken); - response.addCookie(refreshTokenCookie); + response.addCookie(cookieUtil.createAuthCookie(newAccessToken)); + response.addCookie(cookieUtil.createRefreshCookie(newRefreshToken)); - return TokenResponse.of(newAccessToken); + return TokenResponse.of(newAccessToken); + } catch (JwtException e) { + response.addCookie(cookieUtil.createExpiredCookie(jwtProperties.getRefreshTokenCookieName())); + throw new BadRequestException("유효하지 않은 리프레시 토큰입니다. 다시 로그인해주세요."); + } } - private String extractRefreshToken(HttpServletRequest request) { + private Optional extractRefreshToken(HttpServletRequest request) { if (request.getCookies() == null) { - throw new BadRequestException("리프레시 토큰이 없습니다. 다시 로그인해주세요."); + return Optional.empty(); } - for (Cookie cookie : request.getCookies()) { - if (jwtProperties.getRefreshTokenCookieName().equals(cookie.getName())) { - return cookie.getValue(); - } - } - throw new BadRequestException("리프레시 토큰이 없습니다. 다시 로그인해주세요."); + return Arrays.stream(request.getCookies()) + .filter(cookie -> jwtProperties.getRefreshTokenCookieName().equals(cookie.getName())) + .map(Cookie::getValue) + .findFirst(); } } \ No newline at end of file diff --git a/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java b/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java index b4dfc4a..e49c9cf 100644 --- a/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java +++ b/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java @@ -1,6 +1,9 @@ package com.mycom.socket.auth.jwt; import com.mycom.socket.auth.config.JWTProperties; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import lombok.extern.slf4j.Slf4j; @@ -18,6 +21,12 @@ public class JWTUtil { private final SecretKey secretKey; private final JWTProperties jwtProperties; + /** + * JWTUtil 생성자 + * 설정된 시크릿 키를 바탕으로 HMAC-SHA 알고리즘용 SecretKey를 생성합니다. + * + * @param jwtProperties JWT 관련 설정값을 담고 있는 프로퍼티 객체 + */ public JWTUtil(JWTProperties jwtProperties) { this.jwtProperties = jwtProperties; this.secretKey = Keys.hmacShaKeyFor( @@ -26,58 +35,99 @@ public JWTUtil(JWTProperties jwtProperties) { } /** - * 액세스 토큰 생성 + * JWT Parser 생성 + * 토큰 검증 및 정보 추출에 사용되는 공통 Parser를 생성합니다. + * + * @return 설정된 JWT Parser 객체 */ - public String createAccessToken(String email) { - return createToken(email, jwtProperties.getAccessTokenValidityInSeconds()); + private JwtParser createParser() { + return Jwts.parser() + .verifyWith(secretKey) + .requireIssuer(jwtProperties.getIssuer()) + .build(); } - /** - * 리프레시 토큰 생성 - */ - public String createRefreshToken(String email) { - return createToken(email, jwtProperties.getRefreshTokenValidityInSeconds()); - } /** * JWT 토큰 생성 + * 주어진 이메일과 유효기간으로 새로운 JWT를 생성합니다. + * + * @param email 토큰에 포함될 사용자 이메일 + * @param validityInSeconds 토큰 유효 기간 (초) + * @return 생성된 JWT 문자열 + * @throws IllegalStateException 토큰 생성 중 오류 발생 시 */ public String createToken(String email, long validityInSeconds) { Date now = new Date(); Date validity = new Date(now.getTime() + (validityInSeconds * 1000)); - return Jwts.builder() - .issuer(jwtProperties.getIssuer()) - .subject(email) - .issuedAt(now) - .expiration(validity) - .signWith(secretKey) - .compact(); + try { + return Jwts.builder() + .issuer(jwtProperties.getIssuer()) + .subject(email) + .issuedAt(now) + .expiration(validity) + .signWith(secretKey) + .compact(); + } catch (JwtException e) { + log.error("토큰 생성 중 오류가 발생했습니다.", e); + throw new IllegalStateException("토큰 생성 중 오류가 발생했습니다.", e); + } } /** * 토큰 유효성 검증 + * 주어진 토큰이 유효한지 검사합니다. 토큰의 서명, 만료 여부, 발급자 등을 확인합니다. + * + * @param token 검증할 JWT 문자열 + * @return 토큰이 유효하면 true, 그렇지 않으면 false */ public boolean validateToken(String token) { - try { - if (!StringUtils.hasText(token)) { - return false; - } + if (!StringUtils.hasText(token)) { + return false; + } + try { Jwts.parser() .verifyWith(secretKey) .requireIssuer(jwtProperties.getIssuer()) .build() .parseSignedClaims(token); - return true; - } catch (Exception e) { - log.warn("JWT 토큰 검증 실패", e); + + Date expiration = getExpirationFromToken(token); + return new Date().before(expiration); + } catch (ExpiredJwtException e) { + log.warn("만료된 JWT 토큰입니다."); + return false; + } catch (JwtException e) { + log.warn("유효하지 않은 JWT 토큰입니다.", e); return false; } } /** - * 토큰에서 이메일 추출 + * 토큰의 만료 시간 추출 + * + * @param token JWT 문자열 + * @return 토큰의 만료 시간 + */ + private Date getExpirationFromToken(String token) { + return Jwts.parser() + .verifyWith(secretKey) + .build() + .parseSignedClaims(token) + .getPayload() + .getExpiration(); + } + + + /** + * 토큰에서 사용자 이메일 추출 + * JWT의 subject 클레임에서 사용자 이메일을 추출합니다. + * + * @param token JWT 문자열 + * @return 토큰에 포함된 사용자 이메일 + * @throws IllegalStateException 토큰에서 이메일을 추출할 수 없는 경우 */ public String getEmail(String token) { return Jwts.parser() From ed35dc5b01d2d1d1192382c20239f4d5f2c95430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Tue, 14 Jan 2025 20:28:08 +0900 Subject: [PATCH 05/11] =?UTF-8?q?:recycle:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/mycom/socket/auth/service/AuthService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/mycom/socket/auth/service/AuthService.java b/src/main/java/com/mycom/socket/auth/service/AuthService.java index a8c8f4f..0f3b659 100644 --- a/src/main/java/com/mycom/socket/auth/service/AuthService.java +++ b/src/main/java/com/mycom/socket/auth/service/AuthService.java @@ -106,12 +106,12 @@ public RegisterResponse register(RegisterRequest request) { /** * 로그아웃 처리 - * Authorization 쿠키를 무효화하여 로그아웃 처리 + * Access Token과 Refresh Token 쿠키를 무효화하여 로그아웃을 수행합니다. * - * @param response HTTP 응답 객체 (쿠키 무효화용) + * @param response HTTP 응답 객체 */ public void logout(HttpServletResponse response) { - response.addCookie(cookieUtil.createExpiredAuthCookie()); // CookieUtil 사용 - response.addCookie(cookieUtil.createExpiredRefreshCookie()); + response.addCookie(cookieUtil.createExpiredCookie(jwtProperties.getAccessTokenCookieName())); + response.addCookie(cookieUtil.createExpiredCookie(jwtProperties.getRefreshTokenCookieName())); } } From 230cb358c24ebbc052e9e18ac034b92fc61e3a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Tue, 14 Jan 2025 20:29:47 +0900 Subject: [PATCH 06/11] =?UTF-8?q?:recycle:=20=ED=95=84=ED=84=B0=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mycom/socket/auth/security/LoginFilter.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mycom/socket/auth/security/LoginFilter.java b/src/main/java/com/mycom/socket/auth/security/LoginFilter.java index 7ce4aad..2992d39 100644 --- a/src/main/java/com/mycom/socket/auth/security/LoginFilter.java +++ b/src/main/java/com/mycom/socket/auth/security/LoginFilter.java @@ -1,6 +1,7 @@ package com.mycom.socket.auth.security; import com.fasterxml.jackson.databind.ObjectMapper; +import com.mycom.socket.auth.config.JWTProperties; import com.mycom.socket.auth.jwt.JWTUtil; import com.mycom.socket.global.dto.ApiResponse; import com.mycom.socket.auth.dto.request.LoginRequest; @@ -28,6 +29,7 @@ public class LoginFilter extends UsernamePasswordAuthenticationFilter { private final AuthenticationManager authenticationManager; private final CookieUtil cookieUtil; private final ObjectMapper objectMapper; + private final JWTProperties jwtProperties; @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) @@ -51,8 +53,15 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR MemberDetails memberDetails = (MemberDetails) authResult.getPrincipal(); Member member = memberDetails.getMember(); - String accessToken = jwtUtil.createAccessToken(member.getEmail()); //액세스 토큰 생성 - String refreshToken = jwtUtil.createRefreshToken(member.getEmail()); //리프레시 토큰 생성 + // JWT 토큰 생성 + String accessToken = jwtUtil.createToken( + member.getEmail(), + jwtProperties.getAccessTokenValidityInSeconds() + ); + String refreshToken = jwtUtil.createToken( + member.getEmail(), + jwtProperties.getRefreshTokenValidityInSeconds() + ); // 쿠키 생성 및 설정 Cookie accessTokenCookie = cookieUtil.createAuthCookie(accessToken); //액세스 토큰 쿠키 From c63c7ffdfa3ba9a0a8eb154e104265dddb92a5f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Tue, 14 Jan 2025 21:10:47 +0900 Subject: [PATCH 07/11] =?UTF-8?q?:recycle:=20CSRF=20=EA=B3=B5=EA=B2=A9=20?= =?UTF-8?q?=EB=B0=A9=EC=A7=80=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mycom/socket/auth/security/CookieUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/mycom/socket/auth/security/CookieUtil.java b/src/main/java/com/mycom/socket/auth/security/CookieUtil.java index ace18a4..9ac0431 100644 --- a/src/main/java/com/mycom/socket/auth/security/CookieUtil.java +++ b/src/main/java/com/mycom/socket/auth/security/CookieUtil.java @@ -26,6 +26,7 @@ private Cookie createCookie(String name, String value, long maxAge, boolean secu cookie.setSecure(secure); cookie.setPath("/"); cookie.setMaxAge((int) maxAge); + cookie.setAttribute("SameSite", "Strict"); //CSRF 공격 방지 설정 추가 return cookie; } From 608a2e9b9c7f3493ada5fc5eaa79b224c70c4c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Wed, 15 Jan 2025 13:55:13 +0900 Subject: [PATCH 08/11] =?UTF-8?q?:recycle:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/RefreshController.java | 32 +++++++++---------- .../auth/dto/response/TokenResponse.java | 8 +++-- .../com/mycom/socket/auth/jwt/JWTUtil.java | 23 +++++++++---- .../socket/auth/security/CookieUtil.java | 2 +- .../socket/auth/security/LoginFilter.java | 6 ++-- .../socket/auth/service/AuthService.java | 4 +-- .../socket/member/service/LoginTest.java | 4 +-- 7 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/mycom/socket/auth/controller/RefreshController.java b/src/main/java/com/mycom/socket/auth/controller/RefreshController.java index edb2c28..cf0c70a 100644 --- a/src/main/java/com/mycom/socket/auth/controller/RefreshController.java +++ b/src/main/java/com/mycom/socket/auth/controller/RefreshController.java @@ -24,28 +24,28 @@ public class RefreshController { private final CookieUtil cookieUtil; private final JWTProperties jwtProperties; + @PostMapping("/refresh") public TokenResponse refreshAccessToken(HttpServletRequest request, HttpServletResponse response) { - String refreshToken = extractRefreshToken(request) - .orElseThrow(() -> new BadRequestException("리프레시 토큰이 없습니다. 다시 로그인해주세요.")); + Optional refreshTokenOpt = extractRefreshToken(request); + if (refreshTokenOpt.isEmpty()) { + return TokenResponse.of("리프레시 토큰이 없습니다. 다시 로그인해주세요."); + } - try { - if (!jwtUtil.validateToken(refreshToken)) { - throw new JwtException("Invalid refresh token"); - } + String refreshToken = refreshTokenOpt.get(); + if (!jwtUtil.validateToken(refreshToken, "REFRESH_TOKEN")) { + response.addCookie(cookieUtil.createExpiredCookie(jwtProperties.getRefreshTokenCookieName())); + return TokenResponse.of("유효하지 않은 리프레시 토큰입니다. 다시 로그인해주세요."); + } - String email = jwtUtil.getEmail(refreshToken); - String newAccessToken = jwtUtil.createToken(email, jwtProperties.getAccessTokenValidityInSeconds()); - String newRefreshToken = jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds()); + String email = jwtUtil.getEmail(refreshToken); + String newAccessToken = jwtUtil.createToken(email, jwtProperties.getAccessTokenValidityInSeconds(), "ACCESS_TOKEN"); + String newRefreshToken = jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds(), "REFRESH_TOKEN"); - response.addCookie(cookieUtil.createAuthCookie(newAccessToken)); - response.addCookie(cookieUtil.createRefreshCookie(newRefreshToken)); + response.addCookie(cookieUtil.createAuthCookie(newAccessToken)); + response.addCookie(cookieUtil.createRefreshCookie(newRefreshToken)); - return TokenResponse.of(newAccessToken); - } catch (JwtException e) { - response.addCookie(cookieUtil.createExpiredCookie(jwtProperties.getRefreshTokenCookieName())); - throw new BadRequestException("유효하지 않은 리프레시 토큰입니다. 다시 로그인해주세요."); - } + return TokenResponse.of(newAccessToken); } private Optional extractRefreshToken(HttpServletRequest request) { diff --git a/src/main/java/com/mycom/socket/auth/dto/response/TokenResponse.java b/src/main/java/com/mycom/socket/auth/dto/response/TokenResponse.java index 5d27daa..971ac9a 100644 --- a/src/main/java/com/mycom/socket/auth/dto/response/TokenResponse.java +++ b/src/main/java/com/mycom/socket/auth/dto/response/TokenResponse.java @@ -1,9 +1,11 @@ package com.mycom.socket.auth.dto.response; public record TokenResponse( - String accessToken + String accessToken, + String message, + boolean success ) { - public static TokenResponse of(String accessToken) { - return new TokenResponse(accessToken); + public static TokenResponse of(String message) { + return new TokenResponse(null, message, false); } } diff --git a/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java b/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java index e49c9cf..a3739f1 100644 --- a/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java +++ b/src/main/java/com/mycom/socket/auth/jwt/JWTUtil.java @@ -52,12 +52,13 @@ private JwtParser createParser() { * JWT 토큰 생성 * 주어진 이메일과 유효기간으로 새로운 JWT를 생성합니다. * - * @param email 토큰에 포함될 사용자 이메일 + * @param email 토큰에 포함될 사용자 이메일 * @param validityInSeconds 토큰 유효 기간 (초) + * @param accessToken * @return 생성된 JWT 문자열 * @throws IllegalStateException 토큰 생성 중 오류 발생 시 */ - public String createToken(String email, long validityInSeconds) { + public String createToken(String email, long validityInSeconds, String accessToken) { Date now = new Date(); Date validity = new Date(now.getTime() + (validityInSeconds * 1000)); @@ -67,6 +68,7 @@ public String createToken(String email, long validityInSeconds) { .subject(email) .issuedAt(now) .expiration(validity) + .claim("type", accessToken) .signWith(secretKey) .compact(); } catch (JwtException e) { @@ -82,20 +84,27 @@ public String createToken(String email, long validityInSeconds) { * @param token 검증할 JWT 문자열 * @return 토큰이 유효하면 true, 그렇지 않으면 false */ - public boolean validateToken(String token) { + public boolean validateToken(String token, String expectedType) { if (!StringUtils.hasText(token)) { return false; } try { - Jwts.parser() + var claims = Jwts.parser() .verifyWith(secretKey) .requireIssuer(jwtProperties.getIssuer()) .build() - .parseSignedClaims(token); + .parseSignedClaims(token) + .getPayload(); - Date expiration = getExpirationFromToken(token); - return new Date().before(expiration); + // 토큰 타입 검증 + String tokenType = claims.get("type", String.class); + if (!expectedType.equals(tokenType)) { + log.warn("잘못된 토큰 타입입니다. expected: {}, actual: {}", expectedType, tokenType); + return false; + } + + return new Date().before(claims.getExpiration()); } catch (ExpiredJwtException e) { log.warn("만료된 JWT 토큰입니다."); return false; diff --git a/src/main/java/com/mycom/socket/auth/security/CookieUtil.java b/src/main/java/com/mycom/socket/auth/security/CookieUtil.java index 9ac0431..7cad77e 100644 --- a/src/main/java/com/mycom/socket/auth/security/CookieUtil.java +++ b/src/main/java/com/mycom/socket/auth/security/CookieUtil.java @@ -24,7 +24,7 @@ private Cookie createCookie(String name, String value, long maxAge, boolean secu Cookie cookie = new Cookie(name, value); cookie.setHttpOnly(true); cookie.setSecure(secure); - cookie.setPath("/"); + cookie.setPath("/api/auth"); cookie.setMaxAge((int) maxAge); cookie.setAttribute("SameSite", "Strict"); //CSRF 공격 방지 설정 추가 return cookie; diff --git a/src/main/java/com/mycom/socket/auth/security/LoginFilter.java b/src/main/java/com/mycom/socket/auth/security/LoginFilter.java index 2992d39..c49a940 100644 --- a/src/main/java/com/mycom/socket/auth/security/LoginFilter.java +++ b/src/main/java/com/mycom/socket/auth/security/LoginFilter.java @@ -56,11 +56,13 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR // JWT 토큰 생성 String accessToken = jwtUtil.createToken( member.getEmail(), - jwtProperties.getAccessTokenValidityInSeconds() + jwtProperties.getAccessTokenValidityInSeconds(), + "ACCESS_TOKEN" ); String refreshToken = jwtUtil.createToken( member.getEmail(), - jwtProperties.getRefreshTokenValidityInSeconds() + jwtProperties.getRefreshTokenValidityInSeconds(), + "REFRESH_TOKEN" ); // 쿠키 생성 및 설정 diff --git a/src/main/java/com/mycom/socket/auth/service/AuthService.java b/src/main/java/com/mycom/socket/auth/service/AuthService.java index 0f3b659..d7a6883 100644 --- a/src/main/java/com/mycom/socket/auth/service/AuthService.java +++ b/src/main/java/com/mycom/socket/auth/service/AuthService.java @@ -49,13 +49,13 @@ public LoginResponse login(LoginRequest request, HttpServletResponse response) { } String refreshToken = jwtUtil.createToken(member.getEmail(), - jwtProperties.getRefreshTokenValidityInSeconds()); + jwtProperties.getRefreshTokenValidityInSeconds(), "ACCESS_TOKEN"); Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(refreshToken); response.addCookie(refreshTokenCookie); String accessToken = jwtUtil.createToken(member.getEmail(), - jwtProperties.getAccessTokenValidityInSeconds()); + jwtProperties.getAccessTokenValidityInSeconds(), "ACCESS_TOKEN"); Cookie accessTokenCookie = cookieUtil.createAuthCookie(accessToken); response.addCookie(accessTokenCookie); diff --git a/src/test/java/com/mycom/socket/member/service/LoginTest.java b/src/test/java/com/mycom/socket/member/service/LoginTest.java index 8019f64..3aa2c7a 100644 --- a/src/test/java/com/mycom/socket/member/service/LoginTest.java +++ b/src/test/java/com/mycom/socket/member/service/LoginTest.java @@ -73,7 +73,7 @@ class LoginTest { when(memberRepository.findByEmail(email)).thenReturn(Optional.of(member)); when(passwordEncoder.matches(password, encodedPassword)).thenReturn(true); - when(jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds())).thenReturn(token); + when(jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds(), "ACCESS_TOKEN")).thenReturn(token); when(cookieUtil.createAuthCookie(token)).thenReturn(authCookie); // CookieUtil 동작 정의 // when @@ -85,7 +85,7 @@ class LoginTest { assertEquals(nickname, response.nickname()); verify(memberRepository).findByEmail(email); verify(passwordEncoder).matches(password, encodedPassword); - verify(jwtUtil).createToken(email, jwtProperties.getRefreshTokenValidityInSeconds()); + verify(jwtUtil).createToken(email, jwtProperties.getRefreshTokenValidityInSeconds(), "ACCESS_TOKEN"); verify(cookieUtil).createAuthCookie(token); } From d2e5305d05d010bf2938c3d1fe91beb1f580b032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Wed, 15 Jan 2025 13:57:17 +0900 Subject: [PATCH 09/11] =?UTF-8?q?:recycle:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java b/src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java index dca4486..d235d3d 100644 --- a/src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java +++ b/src/main/java/com/mycom/socket/auth/jwt/JWTFilter.java @@ -31,7 +31,7 @@ protected void doFilterInternal(HttpServletRequest request, FilterChain filterChain) throws ServletException, IOException { try { String token = resolveTokenFromCookie(request); - if (StringUtils.hasText(token) && jwtUtil.validateToken(token)) { + if (StringUtils.hasText(token) && jwtUtil.validateToken(token, "ACCESS_TOKEN")) { setAuthentication(token); } } catch (Exception e) { From f16eaec1e15571d3511373546e28a4f742a0f8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Wed, 15 Jan 2025 17:32:26 +0900 Subject: [PATCH 10/11] =?UTF-8?q?:recycle:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mycom/socket/auth/service/AuthService.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/mycom/socket/auth/service/AuthService.java b/src/main/java/com/mycom/socket/auth/service/AuthService.java index d7a6883..e50676f 100644 --- a/src/main/java/com/mycom/socket/auth/service/AuthService.java +++ b/src/main/java/com/mycom/socket/auth/service/AuthService.java @@ -48,16 +48,20 @@ public LoginResponse login(LoginRequest request, HttpServletResponse response) { throw new BadRequestException("잘못된 비밀번호입니다."); } - String refreshToken = jwtUtil.createToken(member.getEmail(), + // // 먼저 액세스 토큰 생성 + String accessToken = jwtUtil.createToken(member.getEmail(), jwtProperties.getRefreshTokenValidityInSeconds(), "ACCESS_TOKEN"); - Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(refreshToken); - response.addCookie(refreshTokenCookie); + Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(accessToken); - String accessToken = jwtUtil.createToken(member.getEmail(), - jwtProperties.getAccessTokenValidityInSeconds(), "ACCESS_TOKEN"); + // 그 다음 리프레시 토큰 생성 + String refreshToken = jwtUtil.createToken(member.getEmail(), + jwtProperties.getAccessTokenValidityInSeconds(), "REFRESH_TOKEN"); + + Cookie accessTokenCookie = cookieUtil.createAuthCookie(refreshToken); - Cookie accessTokenCookie = cookieUtil.createAuthCookie(accessToken); + // 쿠키 설정 + response.addCookie(refreshTokenCookie); response.addCookie(accessTokenCookie); return LoginResponse.of(member.getEmail(), member.getNickname()); From c25e10d7feabaf5666c7c40a6642718e0a8d03b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=A9=E1=84=8B=E1=85=B2=E1=84=8E=E1=85=A1?= =?UTF-8?q?=E1=86=AB?= Date: Wed, 15 Jan 2025 17:36:06 +0900 Subject: [PATCH 11/11] =?UTF-8?q?:recycle:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mycom/socket/auth/service/AuthService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mycom/socket/auth/service/AuthService.java b/src/main/java/com/mycom/socket/auth/service/AuthService.java index e50676f..fd53044 100644 --- a/src/main/java/com/mycom/socket/auth/service/AuthService.java +++ b/src/main/java/com/mycom/socket/auth/service/AuthService.java @@ -52,13 +52,13 @@ public LoginResponse login(LoginRequest request, HttpServletResponse response) { String accessToken = jwtUtil.createToken(member.getEmail(), jwtProperties.getRefreshTokenValidityInSeconds(), "ACCESS_TOKEN"); - Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(accessToken); + Cookie accessTokenCookie = cookieUtil.createAuthCookie(accessToken); // 그 다음 리프레시 토큰 생성 String refreshToken = jwtUtil.createToken(member.getEmail(), jwtProperties.getAccessTokenValidityInSeconds(), "REFRESH_TOKEN"); - Cookie accessTokenCookie = cookieUtil.createAuthCookie(refreshToken); + Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(refreshToken); // 쿠키 설정 response.addCookie(refreshTokenCookie);