[Spring] Spring Boot 이메일 인증 구현하기 + Redis (2)

2024. 1. 28. 22:52· Spring
목차
  1. 들어가기
  2. 💡 Redis란?
  3. ✔️ 인메모리(In-Memory) 데이터 구조란?
  4. ✔️ Redis 특징
  5. ✔️ Redis 사용 시 주의할 점
  6. ✔️ Redis 사용 이유
  7. 💡 Redis로 인증 코드 관리하기
  8. 1. docker-compose
  9. 2. build.gradle
  10. 3. application.yml
  11. 4. RedisConfig
  12. 5. RedisRepository
  13. 6. RedisRepositoryImpl
  14. 7. RedisService
  15. 8. EmailController
  16. 9. EmailService
  17. 출처

 

 

 

 

 

들어가기

이전 포스팅에서 Spring Boot로 이메일 인증 요청 API를 구현했다.

이번에는 인증 코드에 만료 시간을 부여해서 Redis를 통해 인증 코드를 관리하는 로직을 추가하려고 한다.

먼저 Redis에 대해 가볍게 알아보자 !

 

 

 

 

 

 

💡 Redis란?


Redis (Remote Dictionary Server)
: Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터베이스 관리 시스템이다.
데이터베이스, 캐시, 메시지 브로커로 사용되며, 인메모리(In-Memory) 데이터 구조를 가진 저장소이다.

 

 

출처 : Redis 공식 사이트

 

 

 

✔️ 인메모리(In-Memory) 데이터 구조란?

  • 컴퓨터 메인 메모리(RAM)에 데이터를 올려서 사용하는 구조이다.
  • SSD, HDD 같은 저장 공간에서 데이터를 가져오는 것보다 RAM에 올려진 데이터를 가져오는 속도가 훨씬 빠르다.
  • 인메모리 구조 특성상, 서버에 장애가 발생될 경우 데이터 유실이 발생될 수 있다.



✔️ Redis 특징

  • Key-Value 형식이기 때문에 쿼리를 작성할 필요가 없다.
  • 데이터를 디스크에 올리는 방식이 아니라 메모리에서 처리하기 때문에 속도가 빠르다. (인메모리)
  • String, List, Set 등의 자료 구조를 지원한다.
  • 싱글 스레드로, 한 번에 하나의 명령만 처리한다.

 

 

✔️ Redis 사용 시 주의할 점

  • 인메모리 구조를 가지기 때문에 서버에 장애가 발생됐을 경우에 대한 대비를 해야 한다.
  • 메모리 관리가 중요하다.
  • 싱글 스레드 특성상, 한 번에 하나의 명령만 처리하기 때문에 처리하는데 시간이 오래 걸리는 요청/명령은 피해야 한다.

 

 

✔️ Redis 사용 이유

이메일 인증 코드 만료를 위해 Redis 방식을 선택했다. 이유가 무엇일까!

  1. 메모리에 데이터를 저장하기 때문에 빠른 속도로 데이터에 접근할 수 있다. 따라서, Redis를 캐시로 사용하면 매번 디스크 기반 데이터베이스에서 데이터를 읽어오는 비용을 아낄 수 있다.
  2. Redis는 TTL(Time-To-Live) 기능을 제공한다. 따라서, 데이터의 만료 시간을 설정할 수 있기 때문에 인증 코드 관리에 적합하다.

 

 

 

 

💡 Redis로 인증 코드 관리하기


1. docker-compose

  redis:
    container_name: 컨테이너 이름
    image: redis:latest
    ports:
      - 6379:6379
    volumes:
      - ./redis/data:/data
      - ./redis/conf/redis.conf:/usr/local/conf/redis.conf
    labels:
      - "name=redis"
      - "mode=standalone"
    restart: always
    command: redis-server /usr/local/conf/redis.conf

 

 

2. build.gradle

Redis 의존성을 추가한다.

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

 

 

3. application.yml

redis:
  host: localhost
  port: 6379

 

+ 추가 (2025.03.06)

redis.host 가 deprecated 되었다. 아래와 같이 data.redis.host 로 사용해주면 된다!

data:
 redis:
   host: localhost
   port: 6379

 

4. RedisConfig

@Configuration
public class RedisConfig {

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

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

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(host, port);
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }
}

 

 

5. RedisRepository

public interface RedisRepository {

    String getData(String key);

    boolean existData(String key);

    void setDataExpire(String key, String value, long timeout);

    void deleteData(String key);
}

 

 

6. RedisRepositoryImpl

@Repository
public class RedisRepositoryImpl implements RedisRepository {

    private final RedisTemplate<String, String> redisTemplate;

    public RedisRepositoryImpl(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public String getData(String key) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        return valueOperations.get(key);
    }

    @Override
    public boolean existData(String key) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }

    @Override
    public void setDataExpire(String key, String value, long timeout) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        Duration duration = Duration.ofMillis(timeout);
        valueOperations.set(key, value, duration);
    }

    @Override
    public void deleteData(String key) {
        redisTemplate.delete(key);
    }
}

 

 

7. RedisService

@Service
public class RedisService {

    private final RedisRepositoryImpl redisRepositoryImpl;


    public RedisService(RedisRepositoryImpl redisRepositoryImpl) {
        this.redisRepositoryImpl = redisRepositoryImpl;
    }

    @Transactional(readOnly = true)
    public String getData(String key) {
        return redisRepositoryImpl.getData(key);
    }

    @Transactional(readOnly = true)
    public boolean existData(String key) {
        return redisRepositoryImpl.existData(key);
    }

    @Transactional(readOnly = false)
    public void setDataExpire(String key, String value, long timeout) {
        redisRepositoryImpl.setDataExpire(key, value, timeout);
    }

    @Transactional(readOnly = false)
    public void deleteData(String key) {
        redisRepositoryImpl.deleteData(key);
    }
}

 

 

8. EmailController

@GetMapping(value = "/auth", name = "이메일 인증 코드 확인")
public DataResponse<DataResponseCode> checkMailCode(@RequestParam("receiver") String receiver, @RequestParam("code") String code) {
    DataResponse<DataResponseCode> response = emailService.verifyEmailCode(receiver, code);
    return response;
}

 

 

9. EmailService

@Slf4j
@Service
public class EmailService {

	...
    
    private final RedisService redisService;
    
	...
    
    @Transactional(readOnly = false)
    public DataResponse<DataResponseCode> sendMail(String receiver) {
        try {
        	emailCode = createKey();
            MimeMessage message = createMessage(receiver);

            if (redisService.existData(receiver)) { // 기존에 발급 받았던 인증 코드 삭제
                redisService.deleteData(receiver);
            }

            javaMailSender.send(message);

            redisService.setDataExpire(receiver, emailCode, 3 * 60 * 1000L); // 만료 시간 3분

            return new DataResponse<>(UserSignUpResponseCode.SUCCESS);
        } catch (MessagingException | UnsupportedEncodingException | MailException e) {
            e.printStackTrace();
            return new DataResponse<>(UserSignUpResponseCode.MAIL_SEND_FAILED);
        }
    }
    
    /**
     *  메일 인증 코드 확인
     */
    @Transactional(readOnly = true)
    public DataResponse<DataResponseCode> verifyEmailCode(String email, String code) {
        String userMailCode = redisService.getData(email);

        if (userMailCode == null) {
            return new DataResponse<>(UserSignUpResponseCode.EXPIRED_AUTH_MAIL_CODE);
        }

        if (userMailCode.equals(code)) { // 올바른 인증 코드인 경우
            return new DataResponse<>(UserSignUpResponseCode.SUCCESS);
        }

        else { // 올바르지 않은 인증 코드인 경우
            return new DataResponse<>(UserSignUpResponseCode.INVALID_AUTH_MAIL_CODE);
        }
    }
    
    ...
}

 

 

 

 

 

 

출처

  • Redis란?
  • 이메일 인증받기(2)

 

 

 

긴 글 읽어주셔서 감사합니다 🍀

잘못 작성된 내용은 피드백 주시면 반영하겠습니다 😎

 

 

 

 

 

 

'Spring' 카테고리의 다른 글

[Spring] 스프링 배치(Spring Batch)란? Spring Batch + Scheduler 예제  (0) 2025.03.20
[Spring] Spring Boot 이메일 인증 구현하기 + Redis (1)  (0) 2024.01.25
[Spring] Spring Security와 Filter Chain  (0) 2024.01.10
[Spring] Spock 프레임워크  (0) 2023.12.29
[Spring] Spring MVC 와 MVC2  (0) 2023.12.17
  1. 들어가기
  2. 💡 Redis란?
  3. ✔️ 인메모리(In-Memory) 데이터 구조란?
  4. ✔️ Redis 특징
  5. ✔️ Redis 사용 시 주의할 점
  6. ✔️ Redis 사용 이유
  7. 💡 Redis로 인증 코드 관리하기
  8. 1. docker-compose
  9. 2. build.gradle
  10. 3. application.yml
  11. 4. RedisConfig
  12. 5. RedisRepository
  13. 6. RedisRepositoryImpl
  14. 7. RedisService
  15. 8. EmailController
  16. 9. EmailService
  17. 출처
'Spring' 카테고리의 다른 글
  • [Spring] 스프링 배치(Spring Batch)란? Spring Batch + Scheduler 예제
  • [Spring] Spring Boot 이메일 인증 구현하기 + Redis (1)
  • [Spring] Spring Security와 Filter Chain
  • [Spring] Spock 프레임워크
코냥이
코냥이
코딩하는 고냥이
코냥이
코냥이의 하루
코냥이
전체
오늘
어제
  • 분류 전체보기 (29)
    • 코냥이의 하루 (0)
    • Spring (6)
    • JPA (4)
    • Server (1)
    • Database (2)
    • Network (5)
    • 자료구조 (2)
    • Kotlin (1)
    • Git (3)
    • ETC (5)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • google smtp
  • Filter Chain
  • 배포 전략
  • 인증코드 만료
  • flyway
  • 서버 인증 방식
  • spring data jpa
  • 무중단 배포
  • 배열
  • 데이터베이스 방언
  • 1차 캐시
  • 데이터베이스 마이그레이션
  • 2차 캐시
  • DNS 레코드
  • JPA
  • 토큰 인증 방식
  • git
  • 카나리
  • 블루그린
  • Redis

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
코냥이
[Spring] Spring Boot 이메일 인증 구현하기 + Redis (2)
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.