[Spring] Spring Boot E-mail 인증

IToriginal·2023년 3월 12일
0

Spring Boot

목록 보기
3/3
post-thumbnail

최근 프로젝트를 진행하며 사용자가 회원가입을 진행할 때, 이메일을 통한 본인 인증 방식을 사용하기로 하여 해당 내용에 대해서 알아보았다.
Naver 메일과 Gmail의 방법이 있었는데 공동으로 사용할 아이디가 우선 필요해서 회원가입이 쉬운 Google의 방법을 다루기로 했다.

👨🏻‍💻 사전 작업

🧐 Google 계정 생성

[1] Google에 회원가입을 진행한다.
[2] "Google 계정 관리"에서 "보안" 탭에 들어가서 2단계 인증을 활성화 한다.
[3] 2단계 인증을 받고 앱 비밀번호("보안"-"Google에 로그인")를 선택한다.
[4] 메일, window 컴퓨터(or Mac)를 선택한다.

[5] 발급받은 앱 비밀번호를 사용한다.

🧐 Gmail 이메일 발송 한도

Gmail의 개인 계정의 경우, 일일 전송한도는 하루에 500개 제한이 걸려있다.
Google에서는 각 이메일 주소를 각기 다른 이메일로 계산해서 5명의 수신자에게 보낸 하나의 이메일을 5개의 이메일로 계산한다.

  • 1회 전송 한도: 100개 (메일 당 최대 100명에게 이메일을 전송 가능)
  • 일일 (24시간) 전송 한도: 500개
  • 메일 당 수신자: 외부 500개

🧐 NAVER 메일 발송 한도

  • 시간 한도: 시간 당 최대 30회
  • 1회 전송 한도: 100개

👨🏻‍💻 구현하기

🧐 의존성(Dependency) 추가

build.gradle

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-mail'
}

🧐 Config 파일 추가

EmailConfig

@Configuration
@PropertySource("classpath:email.properties")
public class EmailConfig {
 
    @Value("${mail.smtp.port}")
    private int port;
    @Value("${mail.smtp.socketFactory.port}")
    private int socketPort;
    @Value("${mail.smtp.auth}")
    private boolean auth;
    @Value("${mail.smtp.starttls.enable}")
    private boolean starttls;
    @Value("${mail.smtp.starttls.required}")
    private boolean startlls_required;
    @Value("${mail.smtp.socketFactory.fallback}")
    private boolean fallback;
    @Value("${AdminMail.id}")
    private String id;
    @Value("${AdminMail.password}")
    private String password;
 
    @Bean
    public JavaMailSender javaMailService() {
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
        javaMailSender.setHost("smtp.gmail.com");
        javaMailSender.setUsername(id);
        javaMailSender.setPassword(password);
        javaMailSender.setPort(port);
        javaMailSender.setJavaMailProperties(getMailProperties());
        javaMailSender.setDefaultEncoding("UTF-8");
        return javaMailSender;
    }
    private Properties getMailProperties()
    {
        Properties pt = new Properties();
        pt.put("mail.smtp.socketFactory.port", socketPort);
        pt.put("mail.smtp.auth", auth);
        pt.put("mail.smtp.starttls.enable", starttls);
        pt.put("mail.smtp.starttls.required", startlls_required);
        pt.put("mail.smtp.socketFactory.fallback",fallback);
        pt.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        return pt;
    }
}

🧐 properties 추가

.yml

mail:
  smtp:
    auth: true
    starttls:
      required: true
      enable: true
    socketFactory:
      class: javax.net.ssl.SSLSocketFactory
      fallback: false
    port: 465
    socketFactoryPort: 465
  AdminMail:
    id: 구글 아이디 입력
    password: 발급받은 앱 비밀번호를 입력

🧐 Service 코드 작성

EmailService

public interface EmailService {
    String sendSimpleMessage(String to)throws Exception;
}

EmailServiceImpl

@Service
public class EmailServiceImpl implements EmailService{
 
    @Autowired
    JavaMailSender emailSender;
 
    public static final String ePw = createKey();
 
    private MimeMessage createMessage(String to)throws Exception{
        System.out.println("보내는 대상 : "+ to);
        System.out.println("인증 번호 : "+ePw);
        MimeMessage  message = emailSender.createMimeMessage();
 
        message.addRecipients(RecipientType.TO, to);//보내는 대상
        message.setSubject("이메일 인증 테스트");//제목
 
        String msgg="";
        msgg+= "<div style='margin:20px;'>";
        msgg+= "<h1> 공기어때를 방문해 주셔서 감사합니다. </h1>";
        msgg+= "<br>";
        msgg+= "<p>아래 코드를 복사해 입력해주세요<p>";
        msgg+= "<br>";
        msgg+= "<p>감사합니다.<p>";
        msgg+= "<br>";
        msgg+= "<div align='center' style='border:1px solid black; font-family:verdana';>";
        msgg+= "<h3 style='color:blue;'>회원가입 인증 코드입니다.</h3>";
        msgg+= "<div style='font-size:130%'>";
        msgg+= "CODE : <strong>";
        msgg+= ePw+"</strong><div><br/> ";
        msgg+= "</div>";
        message.setText(msgg, "utf-8", "html");//내용
        message.setFrom(new InternetAddress("properties에 입력한 이메일","limjunho"));//보내는 사람
 
        return message;
    }
 
    public static String createKey() {
        StringBuffer key = new StringBuffer();
        Random rnd = new Random();
 
        for (int i = 0; i < 8; i++) { // 인증코드 8자리
            int index = rnd.nextInt(3); // 0~2 까지 랜덤
 
            switch (index) {
                case 0:
                    key.append((char) ((int) (rnd.nextInt(26)) + 97));
                    //  a~z  (ex. 1+97=98 => (char)98 = 'b')
                    break;
                case 1:
                    key.append((char) ((int) (rnd.nextInt(26)) + 65));
                    //  A~Z
                    break;
                case 2:
                    key.append((rnd.nextInt(10)));
                    // 0~9
                    break;
            }
        }
        return key.toString();
    }
    @Override
    public String sendSimpleMessage(String to)throws Exception {
        // TODO Auto-generated method stub
        MimeMessage message = createMessage(to);
        try{//예외처리
            emailSender.send(message);
        }catch(MailException es){
            es.printStackTrace();
            throw new IllegalArgumentException();
        }
        return ePw;
    }
}

🧐 Controller 코드 작성

@PostMapping("/emailConfirm")
public String emailConfirm(@RequestParam String email) throws Exception {

  String confirm = emailService.sendSimpleMessage(email);

  return confirm;
}

👨🏻‍💻 메일 확인

  • query parameter로 인증번호를 받을 이메일 입력.
  • front에 반환한 인증 코드와 서버 터미널에 찍힌 인증 코드가 같은지 확인.

🔗 Reference

https://limjunho.github.io/2022/08/08/EmailAuthentication.html

profile
👾ISTP의 개발자 도전기🧐

0개의 댓글