메인 플젝 중 refresh token을 저장하기위해 Redis를 활용하기로 하였다.
굳이 refreshToken을 DB에 저장하지 않고 redis를 사용하는 이유는
1. redis 특유의 빠른 액서스 속도,
2. 기한이 정해져 있는 token을 db에 저장했다가 지우기보단 redis에다가 데이터 유효기간을 설정하여 관리하는 것이 나을 것 같아서 이다.
다음은 소스 코드이다
Gradle에 추가
implementation 'org.springframework.boot:spring-boot-starter-data-redis:2.3.1.RELEASE' // 추가
application.yml에 redis 포트번호 추가
spring:
redis:
host: localhost
port: 6379
RefreshToken Entity 추가
@Getter
@AllArgsConstructor
public class RefreshToken {
@Id
private String refreshToken;
private Long usersId;
}
Redis를 사용하는 방법에는 두가지가 있다. Repository 인터페이스를 정의하거나 Redis Template를 사용하는 방법이다.(redisRepository는 트랜잭션을 지원하지 않는다고 한다.)
필자는 Redis Template를 사용하였다.
RedisConfig 추가
@Configuration
public class RedisConfig {
private final String redisHost;
private final int redisPort;
public RedisConfig(@Value("${spring.redis.host}") String redisHost,
@Value("${spring.redis.port}") int redisPort) {
this.redisHost = redisHost;
this.redisPort = redisPort;
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
refreshTokenRepository
@Repository
public class RefreshTokenRepository {
private final RedisTemplate redisTemplate;
public RefreshTokenRepository(final RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void save(final RefreshToken refreshToken) {
ValueOperations<String, Long> valueOperations = redisTemplate.opsForValue();
valueOperations.set(refreshToken.getRefreshToken(), refreshToken.getUsersId());
redisTemplate.expire(refreshToken.getRefreshToken(), 60L, TimeUnit.SECONDS);
}
public Optional<RefreshToken> findById(final String refreshToken) {
ValueOperations<String, Long> valueOperations = redisTemplate.opsForValue();
Long usersId = valueOperations.get(refreshToken);
if(Objects.isNull(usersId)) {
return Optional.empty();
}
return Optional.of(new RefreshToken(refreshToken, usersId));
}
}