Skip to content

Commit

Permalink
feat: RefreshToken을 redis in-memory로 관리한다. (#60)
Browse files Browse the repository at this point in the history
* setting: RefreshTokenRepository를 JpaRepository에서 제외한다.

* refactor: 만료시간을 long type으로 변경하고, @tx를 제거한다.
  • Loading branch information
rlarltj authored Jan 28, 2024
1 parent 1a0a063 commit 7876330
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 30 deletions.
6 changes: 6 additions & 0 deletions src/main/java/com/moneymong/global/config/jpa/JpaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
Expand All @@ -27,6 +29,10 @@
basePackages = {
"com.moneymong"
},
excludeFilters = @ComponentScan.Filter(
type = FilterType.REGEX,
pattern = "com.moneymong.global.security.token.*"
),
entityManagerFactoryRef = "moneyMongEntityManagerFactory",
transactionManagerRef = "moneyMongTransactionManager"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,42 @@
package com.moneymong.global.security.token.entity;

import com.moneymong.global.domain.TimeBaseEntity;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.ZonedDateTime;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.TimeToLive;
import org.springframework.data.redis.core.index.Indexed;

import static lombok.AccessLevel.PROTECTED;

@Entity
@RedisHash(value = "refreshToken")
@Getter
@NoArgsConstructor(access = PROTECTED)
public class RefreshToken extends TimeBaseEntity {


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;

@Column(nullable = false, unique = true)
@Indexed
private String token;

@Column(nullable = false)
private Long userId;

@Column(nullable = false)
private String role;

@Column(nullable = false)
private ZonedDateTime expiredAt;
@TimeToLive
private long expiredAt;

@Builder
private RefreshToken(String token, Long userId, String role, ZonedDateTime expiredAt) {
private RefreshToken(String token, Long userId, String role, long expiredAt) {
this.token = token;
this.userId = userId;
this.role = role;
this.expiredAt = expiredAt;
}

public void renew(String token, ZonedDateTime expiredAt) {
public void renew(String token, long expiredAt) {
this.token = token;
this.expiredAt = expiredAt;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.moneymong.global.security.token.repository;

import com.moneymong.global.security.token.entity.RefreshToken;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;

import java.util.Optional;

public interface RefreshTokenRepository extends JpaRepository<RefreshToken, String> {
public interface RefreshTokenRepository extends CrudRepository<RefreshToken, String> {
Optional<RefreshToken> findByToken(String token);

Optional<RefreshToken> findByUserId(Long userId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.ZonedDateTime;
import java.util.*;

@Service
@RequiredArgsConstructor
public class TokenService {

private static final long ONE_WEEK_IN_MILLI_SECONDS = 604800000L;

private final JwtTokenProvider jwtTokenProvider;
private final RefreshTokenRepository refreshTokenRepository;

@Value("${jwt.expiry-seconds.refresh-token}")
private int refreshTokenExpireSeconds;
private long refreshTokenExpireSeconds;

@Transactional
public Tokens createTokens(AuthUserInfo authUserInfo) {
Long userId = authUserInfo.getUserId();
String role = authUserInfo.getRole();
Expand All @@ -46,39 +46,40 @@ private String createAccessToken(Long userId, String role) {
}

private String createRefreshToken(Long userId, String role) {
long expiredAtInMillis = System.currentTimeMillis() + refreshTokenExpireSeconds * 1000;

RefreshToken refreshToken = RefreshToken.builder()
.token(UUID.randomUUID().toString())
.userId(userId)
.role(role)
.expiredAt(ZonedDateTime.now().plusSeconds(refreshTokenExpireSeconds))
.expiredAt(expiredAtInMillis)
.build();

return refreshTokenRepository.save(refreshToken).getToken();
}

@Transactional
public TokenResponse getAccessTokensByRefreshToken(String refreshToken) {
RefreshToken token = refreshTokenRepository.findByToken(refreshToken)
.orElseThrow(() -> new RefreshTokenNotFoundException(ErrorCode.REFRESH_TOKEN_NOT_FOUND));

validateExpiration(token);

ZonedDateTime oneWeekLater = ZonedDateTime.now().plusWeeks(1);

if (token.getExpiredAt().isBefore(oneWeekLater)) {
if (token.getExpiredAt() < System.currentTimeMillis() + ONE_WEEK_IN_MILLI_SECONDS) {
String renewalRefreshToken = UUID.randomUUID().toString();
token.renew(renewalRefreshToken, refreshTokenExpireSeconds);

token.renew(renewalRefreshToken, ZonedDateTime.now().plusSeconds(refreshTokenExpireSeconds));
refreshTokenRepository.save(token);
}

String accessToken = createAccessToken(token.getUserId(), token.getRole());
return new TokenResponse(accessToken, token.getToken());
}

private void validateExpiration(RefreshToken token) {
ZonedDateTime expiredAt = token.getExpiredAt();
long expiredAt = token.getExpiredAt();
long currentTime = System.currentTimeMillis();

if (expiredAt.isBefore(ZonedDateTime.now())) {
if (expiredAt < currentTime) {
throw new ExpiredTokenException(ErrorCode.REFRESH_TOKEN_EXPIRED);
}
}
Expand All @@ -97,9 +98,8 @@ public JwtAuthenticationToken getAuthenticationByAccessToken(String accessToken)
return new JwtAuthenticationToken(principal, null, authorities);
}

@Transactional
public void deleteRefreshToken(String refreshToken) {
refreshTokenRepository.findById(refreshToken)
refreshTokenRepository.findByToken(refreshToken)
.ifPresent(refreshTokenRepository::delete);
}

Expand Down

0 comments on commit 7876330

Please sign in to comment.