Skip to content

Commit ce3834c

Browse files
joowojrparkjaehak
authored andcommitted
CLAP-61 Docs: 토큰 재발급 API 구현
<footer> - 관련: #21
1 parent 54f83e3 commit ce3834c

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package clap.server.adapter.inbound.web.dto.auth;
2+
3+
public record ReissueTokenResponse(
4+
String accessToken,
5+
String refreshToken
6+
) {
7+
}

src/main/java/clap/server/application/mapper/response/AuthResponseMapper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import clap.server.adapter.inbound.web.dto.auth.LoginResponse;
44
import clap.server.adapter.inbound.web.dto.auth.MemberInfoResponse;
5+
import clap.server.adapter.inbound.web.dto.auth.ReissueTokenResponse;
6+
import clap.server.domain.model.auth.CustomJwts;
57
import clap.server.domain.model.member.Member;
68

79
public class AuthResponseMapper {
@@ -27,4 +29,11 @@ public static MemberInfoResponse toMemberInfoResponse(Member member) {
2729
member.getStatus()
2830
);
2931
}
32+
33+
public static ReissueTokenResponse toReissueTokenResponse(final CustomJwts jwtTokens) {
34+
return new ReissueTokenResponse(
35+
jwtTokens.accessToken(),
36+
jwtTokens.refreshToken()
37+
);
38+
}
3039
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package clap.server.application.port.inbound.auth;
2+
3+
import clap.server.adapter.inbound.web.dto.auth.ReissueTokenResponse;
4+
5+
public interface ReissueTokenUsecase {
6+
ReissueTokenResponse reissueToken(String oldRefreshToken);
7+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package clap.server.application.service.auth;
2+
3+
import clap.server.adapter.inbound.web.dto.auth.ReissueTokenResponse;
4+
import clap.server.application.port.inbound.auth.ReissueTokenUsecase;
5+
import clap.server.application.port.outbound.auth.CommandRefreshTokenPort;
6+
import clap.server.application.port.outbound.auth.LoadRefreshTokenPort;
7+
import clap.server.common.annotation.architecture.ApplicationService;
8+
import clap.server.domain.model.auth.CustomJwts;
9+
import clap.server.domain.model.auth.RefreshToken;
10+
import clap.server.exception.AuthException;
11+
import clap.server.exception.code.AuthErrorCode;
12+
import lombok.RequiredArgsConstructor;
13+
import org.springframework.transaction.annotation.Transactional;
14+
15+
import static clap.server.application.mapper.response.AuthResponseMapper.toReissueTokenResponse;
16+
17+
@ApplicationService
18+
@RequiredArgsConstructor
19+
class ReissueTokenService implements ReissueTokenUsecase {
20+
private final IssueTokenService issueTokenService;
21+
private final LoadRefreshTokenPort loadRefreshTokenPort;
22+
private final CommandRefreshTokenPort commandRefreshTokenPort;
23+
24+
@Transactional
25+
public ReissueTokenResponse reissueToken(String oldRefreshToken) {
26+
Long memberId = issueTokenService.resolveRefreshToken(oldRefreshToken);
27+
RefreshToken newRefreshToken;
28+
try {
29+
newRefreshToken = refresh(memberId, oldRefreshToken,
30+
issueTokenService.issueRefreshToken(memberId).getToken());
31+
} catch (IllegalArgumentException e) {
32+
throw new AuthException(AuthErrorCode.EXPIRED_TOKEN);
33+
} catch (IllegalStateException e) {
34+
throw new AuthException(AuthErrorCode.TAKEN_AWAY_TOKEN);
35+
}
36+
37+
String newAccessToken = issueTokenService.issueAccessToken(memberId);
38+
CustomJwts tokens = CustomJwts.of(newAccessToken, newRefreshToken.getToken());
39+
return toReissueTokenResponse(tokens);
40+
}
41+
42+
private RefreshToken refresh(
43+
Long memberId,
44+
String oldRefreshToken,
45+
String newRefreshToken
46+
) throws IllegalArgumentException, IllegalStateException {
47+
RefreshToken refreshToken = loadRefreshTokenPort.findByMemberId(memberId).orElseThrow(
48+
() -> new AuthException(AuthErrorCode.REFRESH_TOKEN_NOT_FOUND)
49+
);
50+
validateToken(oldRefreshToken, refreshToken);
51+
52+
refreshToken.rotation(newRefreshToken);
53+
commandRefreshTokenPort.save(refreshToken);
54+
return refreshToken;
55+
}
56+
57+
private void validateToken(String oldRefreshToken, RefreshToken refreshToken) {
58+
if (isTakenAway(oldRefreshToken, refreshToken.getToken())) {
59+
commandRefreshTokenPort.delete(refreshToken);
60+
throw new AuthException(AuthErrorCode.REFRESH_TOKEN_MISMATCHED);
61+
}
62+
}
63+
64+
private boolean isTakenAway(String requestRefreshToken, String expectedRefreshToken) {
65+
return !requestRefreshToken.equals(expectedRefreshToken);
66+
}
67+
68+
}

0 commit comments

Comments
 (0)