이메일 인증 구현하기

stoph·2023년 6월 11일
0

회원가입 시, 유효한 이메일인지 인증하는 기능 구현하기

이메일 인증 흐름

  1. 사용자가 이메일을 입력하고 인증번호를 요청
  2. 서버에서 이메일을 받고 무작위로 인증번호를 생성
  3. Key값으로 이메일, Value값으로 인증번호를 설정하여 Redis 서버에 저장
  4. 사용자가 인증번호를 입력 후 인증 요청
  5. 서버에서 사용자가 입력한 인증번호가 일치하는지 확인
    • 인증번호가 일치하면, 클라이언트에게 인증 완료 문구를 응답하고 Redis 서버에서 해당 이메일에 해당하는 행 삭제
    • 인증번호가 일치하지 않으면, 클라이언트에게 인증 실패 문구를 응답
    • 인증 시간이 초과되었으면, 클라이언트에게 인증 시간 초과 문구를 응답

EmailAuthDTO

@Getter
@RedisHash(value = "emailAuth", timeToLive = 180L)
public class EmailAuthDTO {
    
    @Id
    private String email;

    private String authNumber;

    @TimeToLive
    private String expiration;

    public EmailAuthDTO(String email, String authNumber) {
        this.email = email;
        this.authNumber = authNumber;
    }
}
  • Redis 서버에 저장될 자료구조 클래스

MailService

@RequiredArgsConstructor
@Service
public class MailService {
    
    private final JavaMailSender javaMailSender;

    public void sendEmail(String toEmail, String authNumber) {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);

            helper.setTo(toEmail);
            helper.setSubject("인증 번호 요청");                       // 이메일 제목
            helper.setText("인증 번호는 " + authNumber + "입니다.");    // 이메일 내용

            javaMailSender.send(mimeMessage);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }
}
  • 이메일 발송을 담당하는 클래스

Controller

....

// 인증번호 요청
@PostMapping("/auth-number-req")
public ResponseEntity<String> authNumberReq(@RequestBody Map<String, String> param) {
	String email = param.get("email");
    String authNumber = createAuthNumber();  // 무작위 인증번호 생성
	
    // Redis 서버에 이메일 및 인증번호 저장
	EmailAuthDTO saved = repository.save(new EmailAuthDTO(email, authNumber));
	
    // 이메일 발송
	mailService.sendEmail(saved.getEmail(), saved.getAuthNumber());
    
    return new ResponseEntity<String>(authNumber, HttpStatus.OK);
}

// 인증 요청
@PostMapping("/auth-email")
public ResponseEntity<String> authEmail(@RequestBody Map<String, String> param) {
	String email = param.get("email");
    String authNumber = param.get("authNumber");

	Optional<EmailAuthDTO> findById = repository.findById(email);
    
    if (findById.isPresent()) {    // Redis 서버에 존재하는 이메일인 경우
    	EmailAuthDTO data = findById.get();
        if (data.getAuthNumber().equals(authNumber)) {    // 인증번호가 일치하는 경우
        	repository.delete(data);    // 해당 row 삭제
            return new ResponseEntity<String>("인증이 완료되었습니다.", HttpStatus.OK);
        } else {
        	return new ResponseEntity<String>("인증 번호가 일치하지 않습니다.", HttpStatus.BAD_REQUEST);
        }
    // Redis 서버에 존재하지 않는 경우, 시간초과로 처리
    } else {
    	return new ResponseEntity<String>("인증 시간이 초과되었습니다.", HttpStatus.NOT_FOUND);
    }
}

....

0개의 댓글