Skip to content

Commit

Permalink
Merge pull request #25 from Team-Going/feature/20
Browse files Browse the repository at this point in the history
[feat] Jwt 재발급 API 구현
  • Loading branch information
gardening-y authored Jan 7, 2024
2 parents cfbec0c + 3c965fa commit 19c64db
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.doorip.common.ApiResponse;
import org.doorip.common.ApiResponseUtil;
import org.doorip.message.SuccessMessage;
import org.doorip.user.dto.request.UserReissueRequest;
import org.doorip.user.dto.request.UserSignInRequest;
import org.doorip.user.dto.request.UserSignUpRequest;
import org.doorip.user.dto.response.UserResponse;
Expand All @@ -13,21 +14,23 @@
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import static org.doorip.common.Constants.AUTHORIZATION;

@RequiredArgsConstructor
@RequestMapping("/api/users")
@Controller
public class UserApiController {
private final UserService userService;

@PostMapping("/signin")
public ResponseEntity<ApiResponse<?>> signIn(@RequestHeader("Authorization") final String token,
public ResponseEntity<ApiResponse<?>> signIn(@RequestHeader(AUTHORIZATION) final String token,
@RequestBody final UserSignInRequest request) {
final UserResponse response = userService.signIn(token, request);
return ApiResponseUtil.success(SuccessMessage.OK, response);
}

@PostMapping("/signup")
public ResponseEntity<ApiResponse<?>> signUp(@RequestHeader("Authorization") final String token,
public ResponseEntity<ApiResponse<?>> signUp(@RequestHeader(AUTHORIZATION) final String token,
@RequestBody final UserSignUpRequest request) {
final UserResponse response = userService.signUp(token, request);
return ApiResponseUtil.success(SuccessMessage.CREATED, response);
Expand All @@ -44,4 +47,11 @@ public ResponseEntity<ApiResponse<?>> withdraw(@UserId final Long userId) {
userService.withdraw(userId);
return ApiResponseUtil.success(SuccessMessage.OK);
}

@PostMapping("/reissue")
public ResponseEntity<ApiResponse<?>> reissue(@RequestHeader(AUTHORIZATION) final String refreshtoken,
@RequestBody final UserReissueRequest request) {
UserResponse response = userService.reissue(refreshtoken, request);
return ApiResponseUtil.success(SuccessMessage.OK, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.doorip.user.dto.request;

public record UserReissueRequest(
Long userId
) {
}
41 changes: 41 additions & 0 deletions doorip-api/src/main/java/org/doorip/user/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

import lombok.RequiredArgsConstructor;
import org.doorip.auth.jwt.JwtProvider;
import org.doorip.auth.jwt.JwtValidator;
import org.doorip.auth.jwt.Token;
import org.doorip.exception.EntityNotFoundException;
import org.doorip.exception.UnauthorizedException;
import org.doorip.message.ErrorMessage;
import org.doorip.openfeign.apple.AppleOAuthProvider;
import org.doorip.openfeign.kakao.KakaoOAuthProvider;
import org.doorip.user.domain.Platform;
import org.doorip.user.domain.RefreshToken;
import org.doorip.user.domain.User;
import org.doorip.user.dto.request.UserReissueRequest;
import org.doorip.user.dto.request.UserSignInRequest;
import org.doorip.user.dto.request.UserSignUpRequest;
import org.doorip.user.dto.response.UserResponse;
Expand All @@ -29,6 +32,7 @@ public class UserService {
private final UserRepository userRepository;
private final RefreshTokenRepository refreshTokenRepository;
private final JwtProvider jwtProvider;
private final JwtValidator jwtValidator;
private final AppleOAuthProvider appleOAuthProvider;
private final KakaoOAuthProvider kakaoOAuthProvider;

Expand Down Expand Up @@ -61,6 +65,17 @@ public void withdraw(Long userId) {
userRepository.deleteById(userId);
}

@Transactional(noRollbackFor = UnauthorizedException.class)
public UserResponse reissue(String refreshToken, UserReissueRequest request) {
Long userId = request.userId();
validateRefreshToken(refreshToken, userId);
User findUser = getUser(userId);
Token issueToken = jwtProvider.issueToken(userId);
updateRefreshToken(issueToken.refreshToken(), findUser);

return UserResponse.of(issueToken);
}

private String getPlatformId(String token, Platform platform) {
if (platform == APPLE) {
return appleOAuthProvider.getApplePlatformId(token);
Expand Down Expand Up @@ -92,4 +107,30 @@ private void deleteRefreshToken(User user) {
user.updateRefreshToken(null);
refreshTokenRepository.deleteById(user.getId());
}

private void validateRefreshToken(String refreshToken, Long userId) {
try {
jwtValidator.validateRefreshToken(refreshToken);
String storedRefreshToken = getRefreshToken(userId);
jwtValidator.equalsRefreshToken(refreshToken, storedRefreshToken);
} catch (UnauthorizedException e) {
signOut(userId);
throw e;
}
}

private String getRefreshToken(Long userId) {
try {
return getRefreshTokenFromRedis(userId);
} catch (EntityNotFoundException e) {
User findUser = getUser(userId);
return findUser.getRefreshToken();
}
}

private String getRefreshTokenFromRedis(Long userId) {
RefreshToken storedRefreshToken = refreshTokenRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException(ErrorMessage.REFRESH_TOKEN_NOT_FOUND));
return storedRefreshToken.getRefreshToken();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public enum ErrorMessage {
*/
ENTITY_NOT_FOUND(HttpStatus.NOT_FOUND, "e4040", "대상을 찾을 수 없습니다."),
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "e4041", "존재하지 않는 회원입니다."),
REFRESH_TOKEN_NOT_FOUND(HttpStatus.NOT_FOUND, "e4042", "리프레쉬 토큰을 찾을 수 없습니다."),

/**
* 405 Method Not Allowed
Expand Down

0 comments on commit 19c64db

Please sign in to comment.