개발 공부 기록

[SpringBoot] SpringBoot에서 Redis 사용하기(2) 본문

Spring/Development Log

[SpringBoot] SpringBoot에서 Redis 사용하기(2)

나만없서고냥이 2023. 12. 31. 19:46

여기서는 SpringBoot에서 Redis를 적용하는 것을 기반으로, JWT 기반의 인증 시스템에서 refresh token을 저장하는데 Redis를 사용해보겠습니다.


✔️ Redis 설치하기

1. Docker 설치

https://hermeslog.tistory.com/497?category=302346 사이트를 참조하였습니다.

 

2. Docker를 통해 Redis 설치

docker run -d -p 6379:6379 redis

cmd를 통해 위 명령으로 Redis Docker Image를 설치합니다.

 

docker ps

Redis의 CONTAINER ID를 확인합니다. 

 

docker exec -it {container id} /bin/bash

Redis image 컨테이너를 실행시켜 Redis가 정상적으로 실행되도록 합니다.

 

redis-cli

redis 서버에 접속합니다.

 


✔️ SpringBoot에 Redis 설정하기

1. build.gradle에 dependency 추가하고 빌드

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

 

2. application.yml에 host와 port 설정

data:
    redis:
        host: localhost
        port: 6379

 

3. Redis 사용을 위한 Configuration 클래스 작성

@Slf4j
@Configuration
@EnableRedisRepositories
public class RedisConfig {
    @Value("${spring.data.redis.host}")
    private String redisHost;

    @Value("${spring.data.redis.port}")
    private int redisPort;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        log.info("host : " + redisHost);
        log.info("port : " + redisPort);
        return new LettuceConnectionFactory(redisHost, redisPort);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        return redisTemplate;
    }
}
  • redisConnectionFactory() : Redis를 연결하기 위한 RedisConnectionFactory를 생성하는 방법을 정의합니다. 호스트와 포트를 설정할 수 있는 Redis 단독 구성을 제공하는 RedisStandaloneConfiguration 객체를 사용하여 LettuceConnectionFactory를 생성합니다.
  • redisTemplate() : Redis에 데이터를 저장하기 위한 Spring Redis 템플릿을 정의합니다. 여기서는 key와 value의 직렬화에 StringRedisSerializer를 사용하며,  객체를 문자열로 변환하여 Redis에 저장합니다. 이렇게 serializer 설정으로 redis-cli를 통해 직접 데이터를 조회할 수 있도록 합니다.

✔️ Redis Template 사용하기

@Service
@RequiredArgsConstructor
public class RedisService {
    private final RedisTemplate<String, Object> redisTemplate;

    public void setValues(String key, String value, long duration) {
        ValueOperations<String, Object> values = redisTemplate.opsForValue();
        values.set(key, value, duration, TimeUnit.MILLISECONDS);
    }

    public String getValues(String key) {
        ValueOperations<String, Object> values = redisTemplate.opsForValue();
        return (String) values.get(key);
    }

    public void deleteValues(String key) {
        redisTemplate.delete(key);
    }

    public boolean checkExistsValue(String value) {
        ValueOperations<String, Object> values = redisTemplate.opsForValue();
        return values.get(value) != null;
    }
}
  • setValues() : key, value와 만료기한을 Redis에 저장합니다.
  • getValues() : 파라미터로 받은 key를 기반으로 데이터를 조회합니다.
  • deleteValues() : 파라미터로 받은 key를 기반으로 데이터를 삭제합니다.
  • checkExistsValue() : 조회하려는 데이터가 없으면 false를 반환합니다.

✔️ Redis 사용하기

1. RefreshTokenService.java

@Service
@RequiredArgsConstructor
public class RefreshTokenService {
    private static final String REFRESH_TOKEN_KEY = "RTK:";
    private final RedisService redisService;
    private final JwtTokenizer jwtTokenizer;

    @Transactional
    public void addRefreshToken(String email, String refreshToken) {
        redisService.setValues(REFRESH_TOKEN_KEY + email, refreshToken);
    }

    @Transactional
    public void deleteRefreshToken(String email) {
        redisService.deleteValues(REFRESH_TOKEN_KEY + email);
    }

    public LoginResponse reissueAccessToken(RefreshTokenDto refreshTokenDto) {
        String email = jwtTokenizer.extractEmailFromToken(refreshTokenDto.getRefreshToken());
        String refreshToken = redisService.getValues(REFRESH_TOKEN_KEY + email);

        if (refreshToken.isEmpty() || !refreshToken.equals(refreshTokenDto.getRefreshToken())) {
            throw new CustomException(CustomResponseCode.INVALID_REFRESH_TOKEN);
        }

        String newAccessToken = jwtTokenizer.createAccessToken(email);

        return LoginResponse.builder()
                .accessToken(newAccessToken)
                .refreshToken(refreshTokenDto.getRefreshToken())
                .accessTokenExpirationTime(jwtTokenizer.refreshTokenExpiration)
                .build();
    }
}

위의 경우, refresh token을 추가, 삭제, 재발급하는 과정에서 redis를 데이터베이스 용도로 사용하였습니다.