build.gradle
// 이메일 인증을 위한 설정
implementation 'org.springframework.boot:spring-boot-starter-mail'
EmailConfig
package com.cloneweek.hanghaebnb.util.email;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import java.util.Properties;
@Configuration
@PropertySource("classpath:application-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;
}
}
EmailController
package com.cloneweek.hanghaebnb.util.email;
import com.cloneweek.hanghaebnb.dto.RequestDto.DupliCheckDto;
import com.cloneweek.hanghaebnb.dto.ResponseDto.ResponseBoolDto;
import com.cloneweek.hanghaebnb.util.exception.StatusMsgCode;
import com.cloneweek.hanghaebnb.dto.ResponseDto.ResponseMsgDto;
import com.cloneweek.hanghaebnb.dto.RequestDto.SignupRequestDto;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.Map;
import static com.cloneweek.hanghaebnb.util.exception.StatusMsgCode.EXIST_NICK;
import static com.cloneweek.hanghaebnb.util.exception.StatusMsgCode.NICKNAME;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users/email")
public class EmailController {
private final EmailService emailService;
// 입력한 이메일로 인증코드 발송
@PostMapping("/confirm")
public ResponseEntity<?> emailConfirm(@RequestBody EmailConfirmDto emailConfirmDto) throws Exception {
emailService.sendSimpleMessage(emailConfirmDto.getEmail());
return ResponseEntity.ok(new ResponseMsgDto(StatusMsgCode.EMAIL_CONFIRM));
}
// 인증코드 발송받은 이메일과 인증번호 입력
@PostMapping("/verifycode")
public ResponseEntity<ResponseMsgDto> verifyCode(@RequestParam String issuedCode, String email) {
// return emailService.verifyCode(issuedCode, email);
return ResponseEntity.ok(emailService.verifyCode(issuedCode, email));
}
// 회원가입 로직
@PostMapping("/signup")
public ResponseEntity<ResponseMsgDto> emailSignup(@RequestBody @Valid SignupRequestDto dto) {
emailService.emailSignup(dto);
return ResponseEntity.ok(new ResponseMsgDto(StatusMsgCode.SIGN_UP));
}
}
EmailEntity
package com.cloneweek.hanghaebnb.util.email;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter
@Entity
@NoArgsConstructor
public class Code {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String randomCode;
public Code(String randomCode, String email) {
this.randomCode = randomCode;
this.email = email;
}
}
EmailConfirmDto
package com.cloneweek.hanghaebnb.util.email;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class EmailConfirmDto {
private String email;
}
EmailRepository
package com.cloneweek.hanghaebnb.util.email;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface CodeRepository extends JpaRepository<Code, Long> {
List<Code> findByEmail(String email);
Code findByEmailAndId(String email, Long id);
}
EmailService
package com.cloneweek.hanghaebnb.util.email;
import com.cloneweek.hanghaebnb.dto.ResponseDto.ResponseBoolDto;
import com.cloneweek.hanghaebnb.dto.ResponseDto.ResponseMsgDto;
import com.cloneweek.hanghaebnb.util.exception.CustomException;
import com.cloneweek.hanghaebnb.dto.RequestDto.SignupRequestDto;
import com.cloneweek.hanghaebnb.entity.User;
import com.cloneweek.hanghaebnb.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.List;
import java.util.Random;
import static com.cloneweek.hanghaebnb.util.exception.StatusMsgCode.*;
@Service
@RequiredArgsConstructor
public class EmailService {
private final JavaMailSender emailSender;
private final PasswordEncoder passwordEncoder;
private final UserRepository userRepository;
private final CodeRepository codeRepository;
// 랜덤하게 만든 인증코드 메일로 발송하는 메서드
public String sendSimpleMessage(String email) throws Exception {
if (userRepository.findByEmail(email).isPresent()) {
throw new CustomException(EXIST_USER);
}
String randomCode = "";
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;
}
}
randomCode = key.toString();
// 메세지 내용 작성
MimeMessage message = emailSender.createMimeMessage();
message.addRecipients(MimeMessage.RecipientType.TO, email);
message.setSubject("hanghaebnb 회원가입 이메일 인증");
String msgg = "";
msgg += "<div style='margin:100px;'>";
msgg += "<h1> 안녕하세요 hanghaebnb입니다. </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 += randomCode + "</strong><div><br/> ";
msgg += "</div>";
message.setText(msgg, "utf-8", "html");//내용
message.setFrom(new InternetAddress("hanghaebnb@gmail.com", "test"));//보내는 사람
// 메세지 발송
try {
emailSender.send(message);
} catch (MailException es) {
es.printStackTrace();
throw new IllegalArgumentException();
}
// 만들었던 랜덤코드 DB에 저장하기
Code code = new Code(randomCode, email);
codeRepository.save(code);
return randomCode;
}
// 회원가입
public void emailSignup(SignupRequestDto dto) {
String email = dto.getEmail();
String password = passwordEncoder.encode(dto.getPassword());
String nickname = dto.getNickname();
// DB에 이메일과 닉네임 중복 있는지 체크
if (userRepository.findByEmail(email).isPresent()) {
throw new CustomException(EXIST_USER);
}
if (userRepository.findByNickname(nickname).isPresent()) {
throw new CustomException(EXIST_NICK);
}
// DB에 회원가입할 데이터 저장. builder 패턴으로 적용해봄.
// User user = new User(email, password, nickname);
User user = User.builder().email(email)
.kakaoNickname(nickname)
.password(password)
.build(); // 생성자 호출
userRepository.save(user);
}
// 이메일로 받은 랜덤코드 대조
public ResponseMsgDto verifyCode(String issuedCode, String email) {
// 리파지토리에서 해당 이메일로 저장된 모든 랜덤코드 불러오기
// 리파지토리에서 불러온 랜덤코드 중 가장 최신순으로 발행된 코드 찾기
List<Code> codeList = codeRepository.findByEmail(email);
long id = 0L;
for (Code code : codeList) {
if (code.getId() > id) {
id = code.getId();
}
}
// 해당 email로 보낸 가장 최신 랜덤코드 불러오기
Code code = codeRepository.findByEmailAndId(email, id);
Boolean result = code.getRandomCode().equals(issuedCode);
return new ResponseBoolDto(result? MATCH_CODE : UNMATCH_CODE, result);
}
}
Email Properties
mail.smtp.auth=true
mail.smtp.starttls.required=true
mail.smtp.starttls.enable=true
mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
mail.smtp.socketFactory.fallback=false
mail.smtp.port=465
mail.smtp.socketFactory.port=465
#admin ?? ??
AdminMail.id= 계정 이메일 주소
AdminMail.password= 계정 이메일 비밀번호
[ 참고 자료 ]
https://hyunmin1906.tistory.com/276
https://javaju.tistory.com/100
https://badstorage.tistory.com/38
'항해99 개발 일지 > [7주차] 클론 프로젝트' 카테고리의 다른 글
[08] 에러처리 Exception (0) | 2023.01.01 |
---|---|
[07] Swagger (0) | 2023.01.01 |
[05] Spring 페이징처리 + 키워드 검색기능 구현 (0) | 2022.12.30 |
[04] OAuth 2.0 카카오 로그인 구현 (0) | 2022.12.28 |
[03] S3 이미지파일 다중업로드 (0) | 2022.12.27 |