SpringBoot 이메일 인증 (redis, smtp활용)

jimmy·2024년 2월 24일
1

프로젝트

목록 보기
1/7

진행중인 프로젝트에서 학교 이메일 인증이 필요하여 이메일 인증에 대한 코드를 작성하게 되었다.

🙋‍♀️ redis가 무엇이며 선택한 이유?
A. redis란 인메모리 데이터 저장소로 빠른 응답 시간, 데이터 만료 기능을 제공하기 때문에 제한된 시간 동안만 유효한 이메일 관련 데이터를 저장하기 적합하다고 판단하였다.

pom.xml

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-mail</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

spring-boot-starter-mail, spring-boot-starter-data-redis 의존성을 추가해주었다.

application.yml

spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: teamwonpage@gmail.com
    password: ${MAIL_PASSWORD}
    properties:
      mail.smtp.auth: true
      mail.smtp.starttls.enable: true

  redis:
    host: localhost
    port: 6379

나는 구글로 host email을 결정하였다. 구글 이메일 port는 587이다.
password는 github에 올라가면 절대 안되기때문에 환경변수 설정을 하는 것을 추천한다.
redis port는 6379이다.
구글 계정에 2단계 인증과 앱 비밀번호를 설정해야하는데, application.yml에 발급받은 앱 비밀번호를 적어주면 된다.
memberApiController

	//이메일 전송 
    @PostMapping("/api/email")
    public ResponseDto sendEmail(@RequestBody EmailSendDto emailDto) {

        String subject = "회원가입 인증 메일입니다.";
        Random random = new Random();
        int code = random.nextInt(9000) + 1000;
        String text = "인증 코드는 " + code + "입니다.";
        memberService.send(emailDto.getEmail(), subject, text, code);
        return new ResponseDto(HttpStatus.OK.value(), "이메일 전송 성공");
    }
    //이메일 인증
    @PostMapping("/api/email/verify")
    public ResponseDto verifyEmail(@RequestBody EmailVerificationDto emailVerificationDto) {
        String email = emailVerificationDto.getEmail();
        String code = emailVerificationDto.getCode(); //사용자가 입력한 코드
        String savedCode = memberService.getVerificationCode(email); //redis에 저장된 코드
        memberService.verificationEmail(code, savedCode);
        return new ResponseDto(HttpStatus.OK.value(), "이메일 인증 성공");
    }

memberService

	private final JavaMailSender mailSender;
    private final StringRedisTemplate redisTemplate;
	//이메일 전송 
    public void send(String email, String subject, String text, int code) {
        long count = getEmailRequestCount(email);
        if (count == 5) {
            throw new RuntimeException("이메일 인증 요청 5번 초과로 24시간 동안 이메일 인증 요청을 할 수 없습니다.");
        }
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(email);
        message.setSubject(subject);
        message.setText(text);
        mailSender.send(message);
        saveVerificationCode(email, String.valueOf(code)); //인증 코드 저장

        increaseEmailRequestCount(email); // 이메일을 보낸 후 요청 횟수를 증가
    }
    //이메일 인증
    public void verificationEmail(String code, String savedCode) {
        if (!code.equals(savedCode)) {
            throw new VerificationFailureException("이메일 인증 실패");
        }
    }
    //redis에서 인증코드 가져오기
    public String getVerificationCode(String email) {
        return redisTemplate.opsForValue().get(email);
    }
    //redis에 인증코드 저장
    public void saveVerificationCode(String email, String code) {
        redisTemplate.opsForValue().set(email, code, 1, TimeUnit.MINUTES); //1분 타임아웃
    }
    //이메일 요청 카운트 증가
    public void increaseEmailRequestCount(String email) {
        String key = "email_request_count:" + email;
        long count = redisTemplate.opsForValue().increment(key);

        if (count == 5) {
            redisTemplate.expire(key, 24, TimeUnit.HOURS);
        }
    }
    //이메일 요청 카운트 가져오기
    public long getEmailRequestCount(String email) {
        String key = "email_request_count:" + email;
        String value = redisTemplate.opsForValue().get(key);
        return value != null ? Long.parseLong(value) : 0;
    }

JavaMailSender 와 StringRedisTemplate 인터페이스를 사용하여 코드를 작성하였다. 인증코드를 radis에 저장하여 1분으로 제한을 두었고, 한 email 당 5번이 넘어가면 24시간동안 이메일 전송이 불가하도록 redis에 count를 저장해두었다.

redis 다운로드
https://github.com/microsoftarchive/redis/releases
msi파일을 다운받는다. -> redis-cli.exe 실행

성공..!

profile
💻BackEnd

0개의 댓글