spring 으로 메일 인증 구현(2)with redis

wellbeing-dough·2024년 1월 5일
1

문제상황

지난번에 인증코드를 DB에서 관리하여 스프링으로 이메일 인증을 구현해봤다 (https://velog.io/@wellbeing-dough/spring-%EC%9C%BC%EB%A1%9C-%EB%A9%94%EC%9D%BC-%EC%9D%B8%EC%A6%9D-%EA%B5%AC%ED%98%84)
하지만 DB에서 인증코드를 관리하면
1. DB Io작업이 빈번하게 일어난다
2. 만료설정이 유연하게 되지않는다

내장 cache (Ehcache) 를 사용할 수 있지만 내장 데이터는 배포할때마다 값이 초기화되기 때문에 rds처럼 외부에서 따로 관리하게 해 두었습니다

고로 Redis를 사용하여 제한 시간 예외처리와 DB커넥션 최소화,Redis의 빠른 응답시간과 유연한 만료 설정을 위해 인증코드를 효과적으로 관리할 수 있게 해보자

해결방안

redis 설치가 끝나고

spring:
  redis:
    host: localhost
    port: 6379

이렇게 6379포트로 redis를 열어두었습니다 배포된 환경에서는 elasticache를 사용했습니다

@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String redisHost;

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

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(redisHost);
        redisStandaloneConfiguration.setPort(Integer.parseInt(redisPort));
        return new LettuceConnectionFactory(redisStandaloneConfiguration);
    }

    @Bean
    public RedisTemplate<Long, String> redisTemplate() {
        RedisTemplate<Long, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new GenericToStringSerializer<>(Long.class));
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(){
        StringRedisTemplate stringRedisTemplate= new StringRedisTemplate();
        stringRedisTemplate.setKeySerializer(new StringRedisSerializer());
        stringRedisTemplate.setValueSerializer(new StringRedisSerializer());
        stringRedisTemplate.setConnectionFactory(redisConnectionFactory());
        return stringRedisTemplate;
    }
}
  1. redisConnectionFactory 메서드는 RedisConnectionFactory를 생성해서 반환한다.
  2. RedisStandaloneConfiguration 객체를 생성하고, redisHost와 redisPort 값을 설정한 다음 LettuceConnectionFactory를 생성해서 반환한다. 이렇게 하면 Redis에 대한 연결을 설정할 수 있다.
  3. redisTemplate 메서드는 RedisTemplate<Long, String>을 생성해서 반환한다. redisConnectionFactory를 사용해서 RedisTemplate 객체를 생성하고, 키와 값을 어떻게 직렬화할지 설정한다. 키는 Long 타입으로, 값은 String 타입으로 직렬화한다. 이렇게 생성된 RedisTemplate은 Redis에 대한 작업을 수행할 수 있는 인스턴스다.
  4. stringRedisTemplate 메서드는 StringRedisTemplate을 생성해서 반환한다.
  5. redisConnectionFactory를 사용해서 StringRedisTemplate 객체를 생성하고, 키와 값을 어떻게 직렬화할지 설정한다. 키와 값 모두 String 타입으로 직렬화한다. 이렇게 생성된 StringRedisTemplate은 Redis에 대한 작업을 수행할 수 있는 인스턴스다.
  6. 이렇게 설정된 RedisConfig 클래스를 사용하면 Redis와의 연결을 설정하고, Redis에 데이터를 저장하고 조회하는 등의 작업을 할 수 있다.

기존 코드(https://velog.io/@wellbeing-dough/spring-%EC%9C%BC%EB%A1%9C-%EB%A9%94%EC%9D%BC-%EC%9D%B8%EC%A6%9D-%EA%B5%AC%ED%98%84)에서 바뀐 부분은

@Service
@RequiredArgsConstructor
public class EmailCacheService {

    private final StringRedisTemplate redisTemplate;

    public String getAndCacheAuthCode(String email) {
        Random random = new Random();
        StringBuilder key = new StringBuilder();

        for(int i=0;i<8;i++) {
            key.append(random.nextInt(10));
        }
        redisTemplate.opsForValue().set(email, key.toString(), 1000L * 60 * 5, TimeUnit.MILLISECONDS);
        return key.toString();
    }

}

여기서 랜덤으로 인증코드를 만들어서 redis에 넣고


    public boolean validEmail(ValidMailInfo info) {

        String cachedAuthCode = redisTemplate.opsForValue().get(info.getEmail()); // 캐시된 인증 코드 가져오기
        log.info("**************************캐싱된 인증 코드" + cachedAuthCode);
        log.info("**************************입력된 인증 코드" + info.getAuthCode());
        return cachedAuthCode != null && cachedAuthCode.equals(info.getAuthCode());
    }

유저의 이메일을 기반으로 인증코드를 검증하는 로직을 추가하면 된다

Timer AOP로 테스트를 해보았다
기존에 DB에서 인증할때는

15미리 세컨드였는데

redis를 사용한 인증 방식에서는

5미리 세컨드가 되었다

0개의 댓글

관련 채용 정보