요즘의 고객들을 비즈니스로 끌어오려면, 과정의 단순함은 필수라고 한다.
- Social Login으로 회원가입/로그인 과정을 단순히 하되
- Social Login에 익숙치 않은 분들을 위해 이메일 로그인 방식을 남겨놓는다~ 라고는 들었지만.. 이는 정확하진 않다! 알아봐야겠다.
2022년 5월 기준, 보안 수준이 낮은 앱의 액세스 설정이 불가능하게 되었다고 한다. 따라서, 다음과정을 통해 앱 비밀번호를 생성해야 한다.
1. 구글 로그인

2. 보안 > 2단계 인증

3. 맨 밑 하단의 앱 비밀번호

4. 앱 선택, 기기 선택


주체를 등록할 때 사용된다.implementation 'org.springframework.boot:spring-boot-starter-mail'
package com.uou.capstone.global.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import java.util.Properties;
@Configuration
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 starttls_required;
@Value("${mail.smtp.socketFactory.fallback}")
private boolean fallback;
@Value("${adminMail.id}") // 발송자 이메일
private String id;
@Value("${adminMail.password}") // 발송자 이메일의 앱 비밀번호
private String password;
@Bean // Bean을 주입시켜서, 다른 서비스 로직에서 이메일을 보내기 위해 사용하기 위함이다.
public JavaMailSender javaMailService() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
// 이메일 서버의 호스트를 설정
javaMailSender.setHost("smtp.gmail.com");
// 이메일 서버에 인증하기 위해 사용자 이름과 비밀번호 설정
// 이메일을 발송할 사람을 인증하는 것임
javaMailSender.setUsername(id);
javaMailSender.setPassword(password);
javaMailSender.setPort(port); // SMTP 서버의 포트를 설정
javaMailSender.setJavaMailProperties(getMailProperties()) // 추가 메일 속성;
javaMailSender.setDefaultEncoding("UTF-8");
return javaMailSender;
}
// 메일 세션 설정에 필요한 Java 메일 속성들을 설정
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", starttls_required);
pt.put("mail.smtp.socketFactory.fallback", fallback);
pt.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // SSLSocketFactory를 사용하여 SSL 연결을 위한 소켓 팩토리를 설정
return pt;
}
}
@Value에서 참조하는 변수들은 yml에서 가져오는 값들이고, 이들을 바로 밑의 변수들에게 주입시켜준다는 의미이다.mail:
smtp:
port: 587
socketFactory:
port: 465
fallback: true
auth: true
starttls:
enable: true
required: true
adminMail:
id: youremail@gmail.com # 여기 본인 메일주소
password: yourpassword # 본인 앱 비밀번호
mail.smtp.port : SMTP 서버의 포트를 설정한다. 587은 일반적으로 SMTP 서버를 위해 사용되는 포트 중 하나이다.mail.smtp.socketFactory.port : 소켓 팩토리를 위한 포트를 설정. 465는 SSL을 통한 SMTP 통신을 위해 일반적으로 사용되는 포트이다.mail.smtp.socketFactory.fallback : 소켓 팩토리 연결이 실패한 경우 폴백(fallback) 연결을 사용할지 여부를 지정한다.mail.smtp.auth : SMTP 인증을 활성화한다.mail.smtp.starttls.enable : STARTTLS를 활성화하여 통신 경로를 암호화한다.mail.smtp.starttls.required : STARTTLS 사용이 필수적인지 지정한다. 이는 메일 서버가 STARTTLS를 지원해야 메일 전송이 가능함을 나타낸다.adminMail.id : 이메일 서비스에서 사용할 관리자의 이메일 ID를 설정한다.adminMail.password : 이메일 서비스에서 사용할 관리자의 이메일 비밀번호를 설정한다. 필자는 구글 계정의 앱 비밀번호를 사용했다.package com.uou.capstone.global.config;
public interface EmailService {
String sendSimpleMessage(String to)throws Exception;
}
package com.uou.capstone.domain.app.user.service;
import com.fasterxml.jackson.databind.ser.Serializers;
import com.uou.capstone.domain.app.user.dto.PostAuthEmailBeforeReq;
import com.uou.capstone.domain.app.user.dto.PostAuthEmailBeforeRes;
import com.uou.capstone.global.config.EmailService;
import com.uou.capstone.global.config.error.exception.BaseException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import javax.mail.Message;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Random;
@Service
@Slf4j
@RequiredArgsConstructor
public class UserService implements EmailService {
private final JavaMailSender emailSender;
public PostAuthEmailBeforeRes emailcheckBefore(PostAuthEmailBeforeReq postAuthEmailBeforeReq) throws BaseException {
try{
sendSimpleMessage(postAuthEmailBeforeReq.getEmail());
}catch (Exception e){
e.printStackTrace();
}
return new PostAuthEmailBeforeRes("Success");
}
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(Message.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("이메일","kimjiseop"));//보내는 사람
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;
}
}
package com.uou.capstone.domain.app.user;
import com.uou.capstone.domain.app.user.dto.PostAuthEmailBeforeReq;
import com.uou.capstone.domain.app.user.dto.PostAuthEmailBeforeRes;
import com.uou.capstone.domain.app.user.service.UserService;
import com.uou.capstone.global.config.error.BaseResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/app")
public class UserController {
private final UserService userService;
@PostMapping("/users/auth/email")
public ResponseEntity<BaseResponse<PostAuthEmailBeforeRes>> emailCheckBefore(@RequestBody PostAuthEmailBeforeReq postAuthEmailBeforeReq){
PostAuthEmailBeforeRes postAuthEmailBeforeRes = userService.emailcheckBefore(postAuthEmailBeforeReq);
return ResponseEntity.ok(new BaseResponse<>(postAuthEmailBeforeRes));
}
}
package com.uou.capstone.domain.app.user.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PostAuthEmailBeforeReq {
private String email;
}
package com.uou.capstone.domain.app.user.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PostAuthEmailBeforeRes {
private String authEmailCheck;
}

