[Spring] 이메일 인증

2023. 8. 26. 11:01Web/Spring

[Spring] 이메일 인증 - Spring Boot Starter Mail 사용

 

개인 학습용 프로젝트에 이메일 인증을 적용하면서 진행했던 과정을 정리하려고 한다.

 

사용한 API는 Spting Boot Starter Mail을 사용하였다.

 

Spting Boot Starter Mail

 

  • Spring Boot에서 제공하는 라이브러리 중 하나
  • 이메일을 보내기 위한 라이브러리
  • JavaMailSender 인터페이스를 구현하여 이메일을 보내는 용도로 사용 가능
  • Spring Boot에서는 JavaMailSender를 자동으로 구성하기에 별도의 설정 없이 사용가능

https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail/3.1.3

 

  • build.gradle에 해당 코드 추가
implementation 'org.springframework.boot:spring-boot-starter-mail:3.1.2'

 

메일 및 환경설정

 

코드를 작성하기 전 사용하고자 하는 메일 계정에서 POP3/SMTP 설정을 해야 한다.

 

  • POP3 / SMTP 설명
    • POP3와 SMTP는 이메일 클라이언트에서 이메일을 보내고 받기 위해 필요한 설정
    •  POP3
      • 이메일을 수신하는 데 사용하는 프로토콜 
      • 단방향 전자 메일 동기화만 지원 
      • 사용자는 서버에서 클라이언트로 전자 메일을 다운로드하는 것만 허용
    • SMTP
      • 이메일 발송을 위해 사용되는 프로토콜
  • 네이버
    • 메일 - 환경설정 - POP3/SMTP 설정

설정 이미지

사용할 정보

설정이 끝나면 사용할 정보를 application.properties 혹은 application.yml 파일에 넣어준다. 만약 해당 정보를 암호화를 하지 않고 사용한다면. gitignore를 해야 한다.

java-mail:
  hostname: ENC(EPeQgROSy1+/Ev6pMXGeYea5cwMwRQlX)
  identifier: ENC(Hfd5ajAKGVf9PldJtig0JQ==)
  password: ENC(dJIuacH5gbfOZHlDDHJkVfZMHaRdXLIa)
  port: ENC(T4AuzQ7+K9X0O3rHuBQieA==)
  required: ENC(+DYTR8SjtLbdeacbFPUBjA==)

이번 프로젝트에서는 yml을 사용하였기에 yml에 다음과 같이 입력하였다.

yml 내부의 ENC()로 적혀있는 부분은 현재 변환이 된 부분이다.

[Etc] application.yml 변경 및 Jasypt (tistory.com)

 

[Etc] application.yml 변경 및 Jasypt

application.yml과 암호화 Applcation.properties vs yml 사용 이유 데이터를 저장하고 읽어오는데 사용하는 포멧 yaml 여러 언어에 쓰이고 같은 configuration 파일을 여러 개의 애플리케이션이 읽기 가능 계층

skyriv312079.tistory.com

 

Config 및 코드

 

- Config 코드

@Configuration
public class EmailConfig {

    @Value("${java-mail.hostname}")
    private String hostname;

    @Value("${java-mail.identifier}")
    private String identifier;

    @Value("${java-mail.password}")
    private String password;

    @Value("${java-mail.port}")
    private String port;

    @Value("${java-mail.required}")
    private String required;


    @Bean
    public JavaMailSender javaMailSender() {
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
        javaMailSender.setHost(hostname);
        javaMailSender.setUsername(identifier);
        javaMailSender.setPassword(password);
        javaMailSender.setPort(Integer.valueOf(port));
        javaMailSender.setJavaMailProperties(getMailProperties());
        return javaMailSender;
    }
    private Properties getMailProperties() {
        Properties properties = new Properties();
        properties.setProperty("mail.smtp.ssl.trust", hostname);
        properties.setProperty("mail.transport.protocol", "smtp");
        properties.setProperty("mail.smtp.auth", required);
        properties.setProperty("mail.smtp.starttls.enable", required);
        properties.setProperty("mail.debug", required);
        properties.setProperty("mail.smtp.ssl.enable", required);
        return properties;
    }

}

- Controller

@RequiredArgsConstructor
@RestController
@RequestMapping(VERIFIED_API_URI)
public class EmailController {

    private final EmailVerifiedService emailVerifiedService;

    @PostMapping("/email")
    public String checkEmailVerified(@RequestParam("email") String email)
        throws MessagingException, UnsupportedEncodingException {
        String emailResponse = emailVerifiedService.sendSimpleMessage(email);
        return emailResponse;
    }
}

- Service


@Service
@RequiredArgsConstructor
@Slf4j
public class EmailVerifiedServiceImpl implements EmailVerifiedService{

    private final JavaMailSender javaMailSender;

    private String ePw;

    @Override
    public MimeMessage createMessage(String to)
        throws MessagingException, UnsupportedEncodingException {
        MimeMessage message = javaMailSender.createMimeMessage();

        message.addRecipients(RecipientType.TO, to);
        message.setSubject("SkillBack 이메일 인증");

        ePw = createKey();

        String msg = "";
        msg += "<div style='margin:100px;>";
        msg += "<h1> 안녕하세요. skillBack 입니다 </h1>";
        msg += "<br>";
        msg += "<p>아래 코드를 창으로 돌아가서 입력하시면 됩니다<p>";
        msg += "<br>";
        msg += "<div align='center' style='border:1px solid black; font-family:verdana';>";
        msg += "<h3 style='color:black;'>인증 코드입니다.</h3>";
        msg += "<div style='font-size:130%'>";
        msg += "CODE : <strong>";
        msg += ePw + "</strong><div><br/> "; // 메일에 인증번호 넣기
        msg += "</div>";

        message.setText(msg, "utf-8", "html");
        message.setFrom(new InternetAddress("gn1007@naver.com", "skill_Admin"));
        return message;
    }

    private String createKey() {
        StringBuffer stringBuffer = new StringBuffer();
        Random random = new Random();

        for (int i = 0; i < 8; i++) {
            int i1 = random.nextInt(3);
            switch (i1) {
                case 0:
                    stringBuffer.append((char) ((int) (random.nextInt(26)) + 97));
                    break;
                case 1 :
                    stringBuffer.append((char) ((int) (random.nextInt(26)) + 65));
                    break;
                case 2:
                    stringBuffer.append((random.nextInt(10)));
                    break;
            }
        }
        return stringBuffer.toString();
    }

    @Override
    public String sendSimpleMessage(String to)
        throws MessagingException, UnsupportedEncodingException {
        MimeMessage message = createMessage(to);
        try {
            javaMailSender.send(message);
        } catch (MailException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("이메일 발송 실패");
        }
        return ePw;

    }
}

Test - PostMan

 

진행하는 프로젝트에서는 이메일 인증의 입력값을 프런트로 전달 후 클라이언트가 입력한 값이 동일한지 프론트 단에서 체크를 할 예정이다. 그렇기에 해당 기능이 잘 작동하는지 postman으로만 테스트를 간단히 진행하였다.