[Spring] Redis와 Email 인증기능 구현

JunWoo An·2023년 12월 14일
0

스파르타코딩클럽

목록 보기
36/46

당초 예정은 ORM에 대해 본격적으로 알아볼 예정이였지만 Redis를 활용한 Email인증구현이라는 하나의 과제를 달성하여 해당 기능구현과정을 먼저 정리해둘려고 한다.

주어진 과제를 보아하니 email or SNS 인증을 구현하는대 인증번호의 유효시간은 5분을 두고 Redis TTL의 특징을 파악하기위해서라면 Redis를 사용해야할듯 싶다.
우선 Redis TTL의 특징을 간략하게 정리하자면 TTL(Time To Live)로 인메모리인 Redis 저장소의 특징으로 저장시 만료시간을 지정하면 해당 만료시간이 지날경우 해당 데이터가 자동으로 삭제되는 기능이다. 이 기능을 활용하여 5분의 만료시간을 지정하면 5분안에 클라이언트가 해당 인증코드가 포함된 회원가입 API를 보내지않을시 해당 인증코드는 무효화 되게 기능을 구현하는 것을 생각할수있다. 아무튼 본격적으로 Email인증 구현전에 Redis를 사용하기위해 해야하는 것들을 정리해보자.

1. Redis 설정

우선 Redis 의존성을 추가하기위해 Gradle에 의존성을 추가해줘야한다.

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

그리고 반드시 까먹지말고 Redis 배포 GitHub에 접속하여 Redis를 설치하여야한다.
Redis GitHub

설치 후 다시 인텔리제이로 돌아와 applicaton.yaml 파일에 들어가 Redis 설정을 해준다.

redis:
  host: localhost
  port: 6379        //기본 포트넘버

다음은 RedisConfig 클래스를 만든 뒤 Redis와 연결하기 위한 설정을 진행해준다.

Bean으로 등록하기 위한 @Configuration@EnableRedisRepositories Redis를 사용하기위한 에노테이션을 반드시 붙힌 후 yaml파일에 저장된 hostport를 불러온다. 다음으로 불러온 host 와 port를 RedisConnectionFactory 클래스를 사용하여 연결 한 후 한가지 데이터타입이 아닌 여러가지 데이터타입을 저장하기위해 RedisTemplate을 정의해 준뒤 cmd창으로 직접 데이터를 조회하기위한 Serializer을 설정해준다.

이제 Redis 연결과 기본 설정이 끝났으면 Redis의 CRUD 서비스를 구현하여야한다.

이번 email 인증기능에선 저장과 삭제, exist체크 정도만 사용하지만 추후 확장성을 고려해 다른 기능또한 구현해두었다. Redis의 기능을 모두 구현하였으니 다음으로는 email기능을 구현해보자.

2. Email 인증

Spring Boot에서는 해당 기능을 간편하게 외부라이브러리 사용으로 구현할수있게 만들어져있다.
마찬가지로 Gradle에 의존성을 추가한다.

    //Mail
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-mail', version: '3.0.5'

또한 yaml파일에 설정을 추가한다.

  mail:
    host: smtp.gmail.com
    port: 587
    username: 이용할 도메인의 로그인한 이메일주소
    password: 이용할 도메인에서 발급받은 비밀번호
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true
          connectiontimeout: 5000
          timeout: 5000
          writetimeout: 5000
    auth-code-expiration-millis: 300000 # 5 * 60 * 1000 == 5분

내 경우는 Gmail을 사용하기위해 SMTP인증을 받아야하기 때문에 인증을 true로 하고 해당 비밀번호를 발급받아 사용하였다. Email 또한 마찬가지로 설정이 끝났으니 요청을 받을 API컨트롤러와 서비스를 만들어야한다. 회원가입 이전에 이메일로 인증을 받고 회원가입을 진행하는것이기 때문에 회원가입API는 별개로 email주소를 포함한 API요청이 오면 해당 이메일로 인증코드를 발송한 후 다시 회원가입API에 해당인증코드를 포함해서 받아 해당 인증코드를 redis에 저장된 인증코드와 비교하여 인증하는 방식으로 설계를 하였다.

회원가입을 포함한 이메일인증컨트롤러는 아래와같다.

Service코드는 일부만 살펴보자면 우선 email 보내는 메서드, 인증코드를 만드는 메서드, email 인증코드가 유효한지 확인하는 메서드이다.

    public void sendCodeToEmail(MailRequestDto mailRequestDto) {
        String email = mailRequestDto.getEmail();

        // email 중복검사
        sameUserInDBByEmail(email);

        String title = "회원가입 이메일 인증 번호";
        String authCode = createCode();
        mailService.sendEmail(email, title, authCode);
        // 이메일 인증 요청 시 인증 번호 Redis에 저장 ( key = "AuthCode " + Email / value = AuthCode )
        redisService.setValues(AUTH_CODE_PREFIX + email,
                authCode, Duration.ofMillis(authCodeExpirationMillis));
    }

    private String createCode() {
        int lenth = 6;
        try {
            Random random = SecureRandom.getInstanceStrong();
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < lenth; i++) {
                builder.append(random.nextInt(10));
            }
            return builder.toString();
        } catch (NoSuchAlgorithmException e) {
            log.debug("UserServiceImpl.createCode() exception occur");
            throw new ApiException(ErrorCode.INTERNAL_SERVER_ERROR);
        }
    }

    private void EmailVerification(String email, String authCode) {
        sameUserInDBByEmail(email);
        String redisAuthCode = redisService.getValues(AUTH_CODE_PREFIX + email);
        if (!(redisService.checkExistsValue(redisAuthCode) && redisAuthCode.equals(authCode))) {
            throw new IllegalArgumentException("인증번호가 틀렸습니다. 다시 입력해주세요.");
        } else {
            redisService.deleteValues(redisAuthCode);
        }
    }

실행 결과는 아래와같다.
PostMan 이메일인증요청

이메일 확인

Redis 콘솔 확인

Post맨 회원가입 성공

5분의 만료시간 이후 결과는 아래와 같다.

만료시간 후 Redis 콘솔

profile
도전하는 사람

0개의 댓글