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"));
이렇게 해두고 테스트를 해보니 기존 로직과 같이 아주 정상적으로 실행됐다!
'백엔드' 카테고리의 다른 글
UPSERT의 동작원리와 기준 컬럼 설정 유의점 (0) | 2025.03.14 |
---|---|
DB의 날짜와 프론트의 날짜 다른(1일 더 차이나는) 오류 해결 (0) | 2025.03.14 |
application-dev.yml 적용하는 방법 (0) | 2025.02.20 |
CORS 오류 해결 방법 - Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. (0) | 2025.02.14 |
자바 컴파일 과정 (0) | 2025.01.14 |