Redis 사용하여 JWT RefreshToken 저장하기

2025. 4. 3. 20:22백엔드

기존에 나는 JWT RefreshToken은 DB에 저장하고 있었는데 이보다 Redis를 사용하여 관리하면 더 좋지 않을까 생각이 들어 로직을 변경해보기로 했다.

 

Redis 로 변경하는 것에 대한 고찰

Redis는 RAM에 데이터를 저장하기 때문에 장애가 나면 데이터가 모두 날아갈수 있다는 단점이 있다. 하지만 RefreshToken은 없어져도 괜찮은 데이터이고 또한 만료시간을 관리해줘야하는데 TTL로 간단히 컨트롤 할 수 있기 때문에 적합해보인다.

2시간 단위로 갱신하는 JWT Access Token은 새롭게 갱신하기 위해 Refresh Token이 필요하다.
이렇게 호출의 빈도가 대체적으로 높은 Refresh Token은 DB에 저장하는 것보다 In-Memory DB에 저장해두고 사용하는 것이 훨씬 속도가 빠르고 병목현상을 방지할 수 있다.

 

 

적용하기 

1. build.gradle에 의존성 주입

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

 

먼저 build.gradle에 Redis 의존성을 주입해준다.

 

 

2-1.  Redis Config 작성

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory); // Redis와 통신할 수 있도록 설정
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); //JSON 형태로 직렬화/역직렬화 해준다
        
        return template;
    }
}

 

Redis를 사용할 수 있도록 설정하는 Config 파일을 작성해준다.

RedisTemplate 객체를 만들어서 우리가 Redis에 데이터를 저장하거나 조회할 때 사용한다. 

 

RedisTemplate<String, Object>

- String: Redis에서 사용할 key의 타입

- Object: Redis에서 사용할 value의 타입

 

 

2-2. RedisService 작성

@Service
public class RedisService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 단순히 key에 value를 저장하는 메서드, TTL 없음
    public void saveData(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    // TTL 설정하면서 저장
    public void saveDataWithTTL(String key, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }
	
    // Redis에 저장된 값을 key를 기반으로 조회
	// key가 존재하지 않으면 null 반환
    public Object getData(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    // key를 Redis에서 삭제
    public void deleteData(String key) {
        redisTemplate.delete(key);
    }
}

 

RedisService는 Redis를 사용해 데이터를 저장, 조회, 삭제할 수 있도록 만들어진 유틸리티 서비스 클래스이다.

 

 

3. Docker에 Redis 실행

docker run -d --name redis -p 6379:6379 redis

 

도커에 Redis 컨테이너를 띄워 실행시켜준다. Redis의 포트는 6379이다.

 

 

4. application.yml에 Redis 설정

data:
  redis:
    host: localhost
    port: 6379

 

일단 로컬에서 테스트해보기 위해 host는 localhost라고 적었다.

 

 

5. Redis에 refreshToken 저장 로직 추가

  • 토큰 저장
// 기존 - DB에 refreshToken 저장
//userRepository.saveRefreshToken(user.get().getId(), refreshToken);

// 변경 - Redis에 저장
redisService.saveDataWithTTL("refresh:" + user.get().getId(), refreshToken, 14, TimeUnit.DAYS );

 

  • accessToken 만료시 refresh토큰 조회
// 기존 - DB에서 Refresh Token 조회
// RefreshResponseDto storedToken = userRepository.findRefreshToken(refreshToken);

// 변경 - 레디스에서 Refresh Token 조회
Object storedToken = redisService.getData("refresh:" + claims.get("userId"));

 

  • 토큰 삭제
// 기존 - DB에서 삭제
//  userRepository.deleteToken(userId);

// 변경 - redis에서 삭제
redisService.deleteData("refresh:" + claims.get("userId"));

 

 

이렇게 해두고 테스트를 해보니 기존 로직과 같이 아주 정상적으로 실행됐다!