RefreshTokenService.java
package qwerty.chaekit.service.member.token;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import qwerty.chaekit.domain.member.Member;
import qwerty.chaekit.domain.member.MemberRepository;
import qwerty.chaekit.domain.member.publisher.PublisherProfile;
import qwerty.chaekit.domain.member.publisher.PublisherProfileRepository;
import qwerty.chaekit.domain.member.user.UserProfile;
import qwerty.chaekit.domain.member.user.UserProfileRepository;
import qwerty.chaekit.dto.member.token.RefreshTokenRequest;
import qwerty.chaekit.dto.member.token.RefreshTokenResponse;
import qwerty.chaekit.global.enums.ErrorCode;
import qwerty.chaekit.global.exception.NotFoundException;
import qwerty.chaekit.global.exception.UnauthorizedException;
import qwerty.chaekit.global.jwt.JwtUtil;
import qwerty.chaekit.global.jwt.TokenParsingResult;
import qwerty.chaekit.global.properties.JwtProperties;
import java.time.Duration;
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class RefreshTokenService {
private final MemberRepository memberRepository;
private final JwtUtil jwtUtil;
private final UserProfileRepository userProfileRepository;
private final PublisherProfileRepository publisherProfileRepository;
private final RedisTemplate<String, String> redisTemplate;
private final JwtProperties jwtProperties;
public RefreshTokenResponse refreshAccessToken(RefreshTokenRequest request) {
String refreshToken = request.refreshToken();
TokenParsingResult parsedToken = jwtUtil.parseRefreshToken(refreshToken);
if (parsedToken.isExpired()) {
throw new UnauthorizedException(ErrorCode.EXPIRED_REFRESH_TOKEN);
}
if (!parsedToken.isValid()) {
throw new UnauthorizedException(ErrorCode.INVALID_REFRESH_TOKEN);
}
if(!redisTemplate.hasKey("refresh:" + refreshToken)) {
throw new UnauthorizedException(ErrorCode.INVALID_REFRESH_TOKEN);
}
Long memberId = parsedToken.memberId();
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new NotFoundException(ErrorCode.MEMBER_NOT_FOUND));
UserProfile user = userProfileRepository.findByMember_Id(memberId).orElse(null);
PublisherProfile publisher = publisherProfileRepository.findByMember_Id(memberId).orElse(null);
String newAccessToken = jwtUtil.createAccessToken(member, user, publisher);
return RefreshTokenResponse.builder()
.accessToken(newAccessToken)
.build();
}
public void logout(RefreshTokenRequest request) {
deleteRefreshToken(request.refreshToken());
}
public String issueRefreshToken(Long memberId) {
String refreshToken = jwtUtil.createRefreshToken(memberId);
saveRefreshToken(refreshToken);
return refreshToken;
}
public void saveRefreshToken(String refreshToken) {
String key = "refresh:" + refreshToken;
redisTemplate.opsForValue().set(key, refreshToken, Duration.ofMillis(jwtProperties.refreshExpirationMs() + 1000));
}
public void deleteRefreshToken(String refreshToken) {
String key = "refresh:" + refreshToken;
redisTemplate.delete(key);
}
}