From 7cb8b76dc6ef354ae3fcdc84a81f0d939215bd25 Mon Sep 17 00:00:00 2001 From: birdie Date: Sat, 20 Jan 2024 22:09:42 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refacotr:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/DuplicatedLoginException.java | 8 ----- .../service/PreventDuplicateLoginService.java | 29 ------------------- 2 files changed, 37 deletions(-) delete mode 100644 src/main/java/yonseigolf/server/user/exception/DuplicatedLoginException.java delete mode 100644 src/main/java/yonseigolf/server/user/service/PreventDuplicateLoginService.java diff --git a/src/main/java/yonseigolf/server/user/exception/DuplicatedLoginException.java b/src/main/java/yonseigolf/server/user/exception/DuplicatedLoginException.java deleted file mode 100644 index 92ebc3f..0000000 --- a/src/main/java/yonseigolf/server/user/exception/DuplicatedLoginException.java +++ /dev/null @@ -1,8 +0,0 @@ -package yonseigolf.server.user.exception; - -public class DuplicatedLoginException extends RuntimeException { - - public DuplicatedLoginException(String message) { - super(message); - } -} diff --git a/src/main/java/yonseigolf/server/user/service/PreventDuplicateLoginService.java b/src/main/java/yonseigolf/server/user/service/PreventDuplicateLoginService.java deleted file mode 100644 index fd9fa0e..0000000 --- a/src/main/java/yonseigolf/server/user/service/PreventDuplicateLoginService.java +++ /dev/null @@ -1,29 +0,0 @@ -package yonseigolf.server.user.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.util.concurrent.TimeUnit; - -@Service -public class PreventDuplicateLoginService { - - private final RedisTemplate redisTemplate; - - @Autowired - public PreventDuplicateLoginService(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - - public void registerLogin(long userId, String token) { - - redisTemplate.opsForValue().set(userId, token, 30, TimeUnit.MINUTES); - } - - // 같으면 true, 다르면 false - public boolean checkDuplicatedLogin(long userId, String token) { - - return redisTemplate.opsForValue().get(userId).equals(token); - } -} From 29f91ed8d02f359976ec2a7412957ddb5f7ada87 Mon Sep 17 00:00:00 2001 From: birdie Date: Sat, 20 Jan 2024 22:09:48 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refacotr:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/config/LoginInterceptor.java | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/main/java/yonseigolf/server/config/LoginInterceptor.java b/src/main/java/yonseigolf/server/config/LoginInterceptor.java index 9b3548c..f518310 100644 --- a/src/main/java/yonseigolf/server/config/LoginInterceptor.java +++ b/src/main/java/yonseigolf/server/config/LoginInterceptor.java @@ -5,11 +5,8 @@ import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import yonseigolf.server.user.dto.response.LoggedInUser; -import yonseigolf.server.user.exception.DuplicatedLoginException; import yonseigolf.server.user.service.JwtService; -import yonseigolf.server.user.service.PreventDuplicateLoginService; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -19,7 +16,6 @@ public class LoginInterceptor implements HandlerInterceptor { private final JwtService jwtUtil; - private final PreventDuplicateLoginService preventDuplicateLoginService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { @@ -33,25 +29,8 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons String token = request.getHeader("Authorization").split(" ")[1]; LoggedInUser loggedInUser = jwtUtil.extractedUserFromToken(token, LoggedInUser.class); - boolean duplicated = preventDuplicateLoginService.checkDuplicatedLogin(loggedInUser.getId(), token); - - if (!duplicated) { - - invalidateRefreshToken(response); - throw new DuplicatedLoginException("중복 로그인이 발생했습니다."); - } - request.setAttribute("userId", loggedInUser.getId()); return true; } - - private void invalidateRefreshToken(HttpServletResponse response) { - Cookie cookie = new Cookie("refreshToken", null); // 쿠키 이름을 Refresh Token 쿠키 이름과 동일하게 설정 - cookie.setHttpOnly(true); - cookie.setSecure(true); // 프로덕션 환경에서는 true로 설정 - cookie.setPath("/"); // Refresh Token 쿠키와 동일한 경로 설정 - cookie.setMaxAge(0); // 쿠키의 만료 시간을 0으로 설정하여 즉시 만료 - response.addCookie(cookie); - } } From 4a0d08b954a298a078422d4d2e102389c0448218 Mon Sep 17 00:00:00 2001 From: birdie Date: Sat, 20 Jan 2024 22:10:19 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refacotr:=20refresh=20token=20=EB=B0=A9?= =?UTF-8?q?=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 --- .../user/controller/UserController.java | 60 +++---------- .../controller/UserExceptionController.java | 8 +- .../user/dto/token/AccessTokenResponse.java | 20 +++++ .../yonseigolf/server/user/entity/User.java | 27 +----- .../user/exception/RefreshTokenException.java | 8 ++ .../user/service/OauthLoginService.java | 29 +++++++ .../server/user/service/UserService.java | 37 ++------ .../user/controller/UserControllerTest.java | 33 +------ .../server/user/entity/UserTest.java | 15 ---- .../server/user/service/UserServiceTest.java | 86 +------------------ 10 files changed, 83 insertions(+), 240 deletions(-) create mode 100644 src/main/java/yonseigolf/server/user/dto/token/AccessTokenResponse.java create mode 100644 src/main/java/yonseigolf/server/user/exception/RefreshTokenException.java diff --git a/src/main/java/yonseigolf/server/user/controller/UserController.java b/src/main/java/yonseigolf/server/user/controller/UserController.java index d2fbb1c..ef8730e 100644 --- a/src/main/java/yonseigolf/server/user/controller/UserController.java +++ b/src/main/java/yonseigolf/server/user/controller/UserController.java @@ -15,10 +15,9 @@ import yonseigolf.server.user.dto.token.KakaoOauthInfo; import yonseigolf.server.user.dto.token.OauthToken; import yonseigolf.server.user.entity.UserClass; -import yonseigolf.server.user.exception.RefreshTokenExpiredException; +import yonseigolf.server.user.exception.RefreshTokenException; import yonseigolf.server.user.service.JwtService; import yonseigolf.server.user.service.OauthLoginService; -import yonseigolf.server.user.service.PreventDuplicateLoginService; import yonseigolf.server.user.service.UserService; import yonseigolf.server.util.CustomResponse; @@ -35,20 +34,18 @@ public class UserController { private final OauthLoginService oauthLoginService; private final KakaoOauthInfo kakaoOauthInfo; private final JwtService jwtUtil; - private final PreventDuplicateLoginService preventDuplicateLoginService; @Autowired - public UserController(UserService userService, OauthLoginService oauthLoginService, KakaoOauthInfo kakaoOauthInfo, JwtService jwtUtil, PreventDuplicateLoginService preventDuplicateLoginService) { + public UserController(UserService userService, OauthLoginService oauthLoginService, KakaoOauthInfo kakaoOauthInfo, JwtService jwtUtil) { this.userService = userService; this.oauthLoginService = oauthLoginService; this.kakaoOauthInfo = kakaoOauthInfo; this.jwtUtil = jwtUtil; - this.preventDuplicateLoginService = preventDuplicateLoginService; } @PostMapping("/oauth/kakao") - public ResponseEntity> kakaoLogin(@RequestBody KakaoCode kakaoCode) { + public ResponseEntity> kakaoLogin(@RequestBody KakaoCode kakaoCode, HttpServletResponse response) { OauthToken oauthToken = oauthLoginService.getOauthToken(kakaoCode.getKakaoCode(), kakaoOauthInfo); KakaoLoginResponse kakaoLoginResponse = oauthLoginService.processKakaoLogin(oauthToken.getAccessToken(), kakaoOauthInfo.getLoginUri()); @@ -59,6 +56,7 @@ public ResponseEntity> kakaoLogin(@RequestBody new Date(new Date().getTime() + 360000) ); + createRefreshToken(response, oauthToken.getRefreshToken()); return ResponseEntity .ok() @@ -76,12 +74,6 @@ public ResponseEntity> signIn(@RequestAttribute Date date = new Date(new Date().getTime() + 3600000); String tokenReponse = jwtUtil.createToken(loggedInUser, date); - // signIn 할 경우 로그인 진행 - makeRefreshToken(response, loggedInUser); - - // redis에 중복 로그인 방지를 위한 access token 저장 - preventDuplicateLoginService.registerLogin(loggedInUser.getId(), tokenReponse); - return ResponseEntity .ok() .body(CustomResponse.successResponse("로그인 성공", @@ -91,14 +83,6 @@ public ResponseEntity> signIn(@RequestAttribute ); } - private void makeRefreshToken(HttpServletResponse response, LoggedInUser loggedInUser) { - - Date expireDate = new Date(new Date().getTime() + 1209600000); - String refreshToken = jwtUtil.createRefreshToken(loggedInUser.getId(), expireDate); - userService.saveRefreshToken(loggedInUser.getId(), refreshToken); - createRefreshToken(response, refreshToken); - } - private void createRefreshToken(HttpServletResponse response, String refreshToken) { Cookie cookie = new Cookie("refreshToken", refreshToken); cookie.setHttpOnly(true); // HTTP Only 설정 @@ -120,43 +104,25 @@ public ResponseEntity> loggedIn() { public ResponseEntity> refreshAccessToken(HttpServletRequest request) { String refreshToken = findRefreshToken(request); + if (refreshToken == null) { + throw new RefreshTokenException("Refresh Token이 존재하지 않습니다."); + } - // refresh token 검증 (null, 만료, 조작) - validateRefreshToken(refreshToken); - - JwtTokenUser jwtTokenUser = jwtUtil.extractedUserFromToken(refreshToken, JwtTokenUser.class); - userService.validateRefreshToken(jwtTokenUser.getId(), jwtUtil); + long kakaoId = oauthLoginService.refreshAccessToken(refreshToken, kakaoOauthInfo); + LoggedInUser loggedInUser = userService.signIn(kakaoId); - // access token 재발급 - String accessToken = userService.generateAccessToken(jwtTokenUser.getId(), jwtUtil, new Date(new Date().getTime() + 3600000)); - preventDuplicateLoginService.registerLogin(jwtTokenUser.getId(), accessToken); + String jwt = jwtUtil.createToken(loggedInUser, new Date(new Date().getTime() + 360000)); return ResponseEntity .ok() .body(CustomResponse.successResponse( "토큰 재발급 성공", JwtTokenResponse.builder() - .accessToken(accessToken) + .accessToken(jwt) .build() )); } - private void validateRefreshToken(String refreshToken) { - - validateRefreshTokenNull(refreshToken); - - if (!jwtUtil.validateTokenIsManipulated(refreshToken) || !jwtUtil.validateTokenIsExpired(refreshToken)) { - throw new RefreshTokenExpiredException("[ERROR] Refresh Token이 만료되었습니다."); - } - } - - private void validateRefreshTokenNull(String refreshToken) { - - if (refreshToken == null) { - throw new RefreshTokenExpiredException("[ERROR] Refresh Token이 존재하지 않습니다."); - } - } - private String findRefreshToken(HttpServletRequest request) { String refreshToken = null; @@ -173,13 +139,9 @@ private String findRefreshToken(HttpServletRequest request) { return refreshToken; } - @PostMapping("/users/logout") public ResponseEntity> logOut(@RequestAttribute Long userId, HttpServletResponse response) { - // refresh toekn 무효화 - userService.invalidateRefreshToken(userId); - // Cookie 삭제 invalidateCookie(response); diff --git a/src/main/java/yonseigolf/server/user/controller/UserExceptionController.java b/src/main/java/yonseigolf/server/user/controller/UserExceptionController.java index 8f85a5f..9048968 100644 --- a/src/main/java/yonseigolf/server/user/controller/UserExceptionController.java +++ b/src/main/java/yonseigolf/server/user/controller/UserExceptionController.java @@ -81,14 +81,14 @@ public ResponseEntity refreshTokenExpired(RefreshTokenExpir )); } - @ExceptionHandler(DuplicatedLoginException.class) - public ResponseEntity duplicatedLogin(DuplicatedLoginException ex) { + @ExceptionHandler(RefreshTokenException.class) + public ResponseEntity refreshTokenException(RefreshTokenException ex) { return ResponseEntity - .status(HttpStatus.CONFLICT) + .status(HttpStatus.UNAUTHORIZED) .body(new CustomErrorResponse( "fail", - 409, + 401, ex.getMessage() )); } diff --git a/src/main/java/yonseigolf/server/user/dto/token/AccessTokenResponse.java b/src/main/java/yonseigolf/server/user/dto/token/AccessTokenResponse.java new file mode 100644 index 0000000..fa4c0a8 --- /dev/null +++ b/src/main/java/yonseigolf/server/user/dto/token/AccessTokenResponse.java @@ -0,0 +1,20 @@ +package yonseigolf.server.user.dto.token; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class AccessTokenResponse { + + + @JsonProperty("token_type") + private String tokenType; + @JsonProperty("access_token") + private String accessToken; + @JsonProperty("expires_in") + private Integer expiresIn; +} diff --git a/src/main/java/yonseigolf/server/user/entity/User.java b/src/main/java/yonseigolf/server/user/entity/User.java index 2a22bcb..bf6cc03 100644 --- a/src/main/java/yonseigolf/server/user/entity/User.java +++ b/src/main/java/yonseigolf/server/user/entity/User.java @@ -5,8 +5,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import yonseigolf.server.user.dto.request.SignUpUserRequest; -import yonseigolf.server.user.exception.RefreshTokenExpiredException; -import yonseigolf.server.user.service.JwtService; import javax.persistence.*; @@ -30,11 +28,7 @@ public class User { private UserRole role; @Enumerated(EnumType.STRING) private UserClass userClass; - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "refresh_token_id") - private RefreshToken refreshToken; - // TODO: 회원가입 시 멤버로 설정할 것 public static User of(SignUpUserRequest request, Long kakaoId) { return User.builder() @@ -44,7 +38,7 @@ public static User of(SignUpUserRequest request, Long kakaoId) { .studentId(request.getStudentId()) .major(request.getMajor()) .semester(request.getSemester()) - .role(UserRole.OB_ASSISTANT_LEADER) + .role(UserRole.MEMBER) .userClass(UserClass.NONE) .build(); } @@ -75,25 +69,6 @@ public boolean isMember() { this.userClass == UserClass.OB; } - public void validateRefreshToken(JwtService jwtUtil) { - // refresh token이 없을 경우 발급한다. - if (this.refreshToken == null) { - return; - } - // refresh token이 만료된 경우 재발급한다. - this.refreshToken.isBeforeExpired(jwtUtil); - } - - public void saveRefreshToken(RefreshToken refreshToken) { - - this.refreshToken = refreshToken; - } - - public void invalidateRefreshToken() { - - this.refreshToken = null; - } - public boolean checkOwner(Long userId) { return this.id == userId; } diff --git a/src/main/java/yonseigolf/server/user/exception/RefreshTokenException.java b/src/main/java/yonseigolf/server/user/exception/RefreshTokenException.java new file mode 100644 index 0000000..69ffe67 --- /dev/null +++ b/src/main/java/yonseigolf/server/user/exception/RefreshTokenException.java @@ -0,0 +1,8 @@ +package yonseigolf.server.user.exception; + +public class RefreshTokenException extends RuntimeException{ + + public RefreshTokenException(String message) { + super(message); + } +} diff --git a/src/main/java/yonseigolf/server/user/service/OauthLoginService.java b/src/main/java/yonseigolf/server/user/service/OauthLoginService.java index 05e5ca4..87bfdda 100644 --- a/src/main/java/yonseigolf/server/user/service/OauthLoginService.java +++ b/src/main/java/yonseigolf/server/user/service/OauthLoginService.java @@ -7,6 +7,7 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import yonseigolf.server.user.dto.response.KakaoLoginResponse; +import yonseigolf.server.user.dto.token.AccessTokenResponse; import yonseigolf.server.user.dto.token.KakaoOauthInfo; import yonseigolf.server.user.dto.token.OauthToken; @@ -68,4 +69,32 @@ private KakaoLoginResponse processLogin(String accessToken, String loginUri) { KakaoLoginResponse.class) .getBody(); } + + public long refreshAccessToken(String refreshToken, KakaoOauthInfo oauthInfo) { + + HttpEntity request = createRefreshRequestEntity(refreshToken, oauthInfo); + ResponseEntity refreshResponse = restTemplate.postForEntity(oauthInfo.getRedirectUri(), request, AccessTokenResponse.class); + + AccessTokenResponse accessResponse = refreshResponse.getBody(); + KakaoLoginResponse kakaoLoginResponse = processKakaoLogin(accessResponse.getAccessToken(), oauthInfo.getLoginUri()); + + return kakaoLoginResponse.getId(); + } + + private HttpEntity createRefreshRequestEntity(String refreshToken, KakaoOauthInfo oauthInfo) { + MultiValueMap headers = new LinkedMultiValueMap<>(); + Map header = new HashMap<>(); + header.put("Accept", "application/json"); + header.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); + headers.setAll(header); + + MultiValueMap requestPayloads = new LinkedMultiValueMap<>(); + Map requestPayload = new HashMap<>(); + requestPayload.put("grant_type", "refresh_token"); + requestPayload.put("client_id", oauthInfo.getClientId()); + requestPayload.put("refresh_token", refreshToken); + requestPayloads.setAll(requestPayload); + + return new HttpEntity<>(requestPayloads, headers); + } } diff --git a/src/main/java/yonseigolf/server/user/service/UserService.java b/src/main/java/yonseigolf/server/user/service/UserService.java index 40ff31b..2269d1a 100644 --- a/src/main/java/yonseigolf/server/user/service/UserService.java +++ b/src/main/java/yonseigolf/server/user/service/UserService.java @@ -6,12 +6,13 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import yonseigolf.server.user.dto.request.SignUpUserRequest; -import yonseigolf.server.user.dto.response.*; -import yonseigolf.server.user.entity.RefreshToken; +import yonseigolf.server.user.dto.response.AdminResponse; +import yonseigolf.server.user.dto.response.LoggedInUser; +import yonseigolf.server.user.dto.response.SingleUserResponse; +import yonseigolf.server.user.dto.response.UserResponse; import yonseigolf.server.user.entity.User; import yonseigolf.server.user.entity.UserClass; import yonseigolf.server.user.entity.UserRole; -import yonseigolf.server.user.repository.RefreshTokenRepository; import yonseigolf.server.user.repository.UserRepository; import java.util.Date; @@ -22,13 +23,11 @@ public class UserService { private final UserRepository userRepository; - private final RefreshTokenRepository refreshTokenRepository; @Autowired - public UserService(UserRepository userRepository, RefreshTokenRepository refreshTokenRepository) { + public UserService(UserRepository userRepository) { this.userRepository = userRepository; - this.refreshTokenRepository = refreshTokenRepository; } public LoggedInUser signUp(SignUpUserRequest request, Long kakaoId) { @@ -68,30 +67,6 @@ public void updateUserClass(Long userId, UserClass userClass) { user.updateUserClass(userClass); } - public void validateRefreshToken(long userId, JwtService jwtUtil) { - // refresh token이 없거나 만료된 경우 재발급 - User user = findById(userId); - user.validateRefreshToken(jwtUtil); - } - - @Transactional - public void saveRefreshToken(long id, String token) { - - User user = findById(id); - RefreshToken refreshToken = RefreshToken.builder() - .refreshToken(token) - .build(); - RefreshToken savedRefreshToken = refreshTokenRepository.save(refreshToken); - user.saveRefreshToken(savedRefreshToken); - } - - @Transactional - public void invalidateRefreshToken(long id) { - - User user = findById(id); - user.invalidateRefreshToken(); - } - public String generateAccessToken(Long userId, JwtService jwtService, Date expiredAt) { User user = findById(userId); LoggedInUser loggedInUser = LoggedInUser.fromUser(user); @@ -105,7 +80,7 @@ private User findById(Long id) { .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 유저입니다.")); } - private User findByKakaoId(Long kakaoId) { + public User findByKakaoId(Long kakaoId) { return userRepository.findByKakaoId(kakaoId) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 유저입니다.")); diff --git a/src/test/java/yonseigolf/server/user/controller/UserControllerTest.java b/src/test/java/yonseigolf/server/user/controller/UserControllerTest.java index 6b78709..a199409 100644 --- a/src/test/java/yonseigolf/server/user/controller/UserControllerTest.java +++ b/src/test/java/yonseigolf/server/user/controller/UserControllerTest.java @@ -21,19 +21,14 @@ import yonseigolf.server.user.entity.UserRole; import yonseigolf.server.user.service.JwtService; import yonseigolf.server.user.service.OauthLoginService; -import yonseigolf.server.user.service.PreventDuplicateLoginService; import yonseigolf.server.user.service.UserService; -import javax.servlet.http.Cookie; -import java.util.Date; import java.util.List; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.when; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; import static org.springframework.restdocs.payload.PayloadDocumentation.*; @@ -54,9 +49,6 @@ class UserControllerTest extends RestDocsSupport { private KakaoOauthInfo kakaoOauthInfo; @Mock private JwtService jwtUtil; - @Mock - private PreventDuplicateLoginService preventDuplicateLoginService; - @Test @DisplayName("카카오톡 로그인을 할 수 있다.") @@ -303,29 +295,6 @@ void updateUserClassTest() throws Exception { )); } - @Test - @DisplayName("유효한 리프레시 토큰으로 액세스 토큰 재발급") - void whenValidRefreshTokenThenIssueNewAccessToken() throws Exception { - // given - String validRefreshToken = "valid.refresh.token"; - String newAccessToken = "new.access.token"; - Long userId = 1L; - JwtTokenUser jwtTokenUser = JwtTokenUser.builder() - .id(1L) - .build(); - - when(jwtUtil.extractedUserFromToken(validRefreshToken, JwtTokenUser.class)).thenReturn(jwtTokenUser); - when(jwtUtil.validateTokenIsExpired(validRefreshToken)).thenReturn(true); - when(jwtUtil.validateTokenIsManipulated(validRefreshToken)).thenReturn(true); - when(userService.generateAccessToken(eq(userId), any(JwtService.class), any(Date.class))).thenReturn(newAccessToken); - - Cookie refreshTokenCookie = new Cookie("refreshToken", validRefreshToken); - - // when & then - mockMvc.perform(post("/users/signIn/refresh").cookie(refreshTokenCookie)) - .andExpect(status().isOk()); - } - @Test @DisplayName("로그아웃 요청 시 쿠키를 무효화하고 정상적인 응답을 반환한다.") void whenLoggingOut_ShouldInvalidateCookie_AndReturnSuccess() throws Exception { @@ -352,6 +321,6 @@ void healthCheck() throws Exception { @Override protected Object initController() { - return new UserController(userService, oauthLoginService, kakaoOauthInfo, jwtUtil, preventDuplicateLoginService); + return new UserController(userService, oauthLoginService, kakaoOauthInfo, jwtUtil); } } diff --git a/src/test/java/yonseigolf/server/user/entity/UserTest.java b/src/test/java/yonseigolf/server/user/entity/UserTest.java index 16e821b..37785b2 100644 --- a/src/test/java/yonseigolf/server/user/entity/UserTest.java +++ b/src/test/java/yonseigolf/server/user/entity/UserTest.java @@ -1,13 +1,10 @@ package yonseigolf.server.user.entity; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import yonseigolf.server.user.service.JwtService; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; class UserTest { @@ -27,16 +24,4 @@ void UserMemberTest(String userClassStr) { // then assertThat(member).isTrue(); } - - @Test - @DisplayName("refreshToken이 없는 유저의 경우 에러가 발생하지 않는다.") - void refreshTokenTest() { - // given - User user = User.builder().build(); - - // when & then - assertThatCode(() -> user.validateRefreshToken(new JwtService())) - .doesNotThrowAnyException(); - } - } diff --git a/src/test/java/yonseigolf/server/user/service/UserServiceTest.java b/src/test/java/yonseigolf/server/user/service/UserServiceTest.java index 82ba5a8..5b9c804 100644 --- a/src/test/java/yonseigolf/server/user/service/UserServiceTest.java +++ b/src/test/java/yonseigolf/server/user/service/UserServiceTest.java @@ -14,12 +14,12 @@ import yonseigolf.server.user.dto.response.AdminResponse; import yonseigolf.server.user.dto.response.LoggedInUser; import yonseigolf.server.user.dto.response.SingleUserResponse; -import yonseigolf.server.user.entity.*; +import yonseigolf.server.user.entity.User; +import yonseigolf.server.user.entity.UserClass; +import yonseigolf.server.user.entity.UserRole; import yonseigolf.server.user.repository.RefreshTokenRepository; import yonseigolf.server.user.repository.UserRepository; -import java.util.Date; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; @@ -197,84 +197,4 @@ void notExistingUserExceptionTest() { .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("존재하지 않는 유저입니다."); } - - @Test - @DisplayName("refresh token에 이상이 없는 경우 예외가 발생하지 않는다.") - void noThrowRefreshTokenTest() { - // given - User user = User.builder() - .kakaoId(1L) - .name("이름") - .phoneNumber("010-1234-5678") - .studentId(1) - .major("컴퓨터과학과") - .semester(1) - .role(UserRole.MEMBER) - .userClass(UserClass.OB) - .build(); - User savedUser = userRepository.save(user); - - String refreshToken = jwtService.createRefreshToken(savedUser.getId(), new Date(new Date().getTime() + 1800000)); - userService.saveRefreshToken(savedUser.getId(),refreshToken); - - // when & then - userService.validateRefreshToken(savedUser.getId(), jwtService); - } - - @Test - @DisplayName("refresh token validate test") - void validateRefreshTokenTest() { - // given - RefreshToken refreshToken = RefreshToken - .builder() - .refreshToken("refreshToken") - .build(); - RefreshToken savedRefreshToken = refreshTokenRepository.save(refreshToken); - - User user = User.builder() - .kakaoId(1L) - .name("이름") - .phoneNumber("010-1234-5678") - .studentId(1) - .major("컴퓨터과학과") - .semester(1) - .role(UserRole.MEMBER) - .userClass(UserClass.OB) - .refreshToken(savedRefreshToken) - .build(); - User savedUser = userRepository.save(user); - - // when - userService.invalidateRefreshToken(savedUser.getId()); - User findUser = userRepository.findById(savedUser.getId()).orElseGet(() -> User.builder().build()); - - // then - assertThat(findUser.getRefreshToken()).isNull(); - } - - @Test - @DisplayName("refresh token을 통해 access token을 재생성 할 수 있다.") - void refreshAccessTokenTest() { - // given - User user = User.builder() - .kakaoId(1L) - .name("이름") - .phoneNumber("010-1234-5678") - .studentId(1) - .major("컴퓨터과학과") - .semester(1) - .role(UserRole.MEMBER) - .userClass(UserClass.OB) - .build(); - User savedUser = userRepository.save(user); - String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJsb2dpbl9tZW1iZXIiLCJ1c2VyUHJvZmlsZSI6eyJpZCI6MzUsIm5hbWUiOiLsnoTrj5ntmIQiLCJhZG1pblN0YXR1cyI6dHJ1ZSwibWVtYmVyU3RhdHVzIjp0cnVlfSwiZXhwIjoxNzAwOTc5MjU5fQ.MegKm0Oj7wYcKMtanyLqt0x5L4X7VC_tfBwJvfGSG1c"; - - userService.saveRefreshToken(savedUser.getId(), token); - - // when - String accessToken = userService.generateAccessToken(savedUser.getId(), jwtService, new Date(new Date().getTime() + 1800000)); - - // then - assertThat(accessToken).isNotNull(); - } }