


비밀번호 반드시 따로 저장
dependencies {
// 메일 전송 위한 라이브러리 추가
implementation 'org.springframework.boot:spring-boot-starter-mail'
}
spring:
mail:
host: smtp.gmail.com
port: 587
username: 이메일보낼name
password: 앱비밀번호
properties:
mail:
smtp:
auth: true # 사전인증 설정
starttls:
enable: true # STL 필수설정
// 1. 이메일 입력받음
public record EmailDuplicationRequest(
String email
) {
}
------------------------------------------------
// 2. 이메일 + 인증코드 검증
public record EmailAuthRequest(
String email,
String authCode
) {
}
package com.ssafy.econimal.domain.auth.service;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import com.ssafy.econimal.domain.auth.dto.request.EmailRequest;
import com.ssafy.econimal.domain.auth.util.HtmlContent;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Service
@RequiredArgsConstructor
@Slf4j
public class AuthEmailSendService {
private final JavaMailSender javaMailSender;
private final AuthEmailService authEmailService;
private final static String EMAIL_SUBJECT = "Econimal Team: 인증코드";
public void handleSendEmail(EmailRequest request) {
// 인증코드 생성
String authCode = authEmailService.generateVerificationCode();
// 인증코드 저장
authEmailService.saveVerificationCode(request.email(), authCode);
// 이메일 전송
sendEmail(request.email(), authCode);
}
// 이메일 보내기
private void sendEmail(String email, String authCode) {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, false, "UTF-8");
helper.setTo(email); // 이메일 받을 사람
helper.setSubject(EMAIL_SUBJECT);
// 이메일 내용, HTML 설정(true)
helper.setText(HtmlContent.emailAuthContent(authCode), true);
javaMailSender.send(mimeMessage);
log.debug("이메일 전송 성공: email: {}, code: {}", email, authCode);
} catch (MessagingException e) {
throw new RuntimeException("알 수 없는 이유로 이메일 전송 실패");
}
}
}
package com.ssafy.econimal.domain.auth.service;
import java.security.SecureRandom;
import java.time.Duration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.ssafy.econimal.domain.auth.dto.request.EmailAuthRequest;
import com.ssafy.econimal.domain.auth.dto.request.UpdatePasswordRequest;
import com.ssafy.econimal.domain.auth.util.AuthValidator;
import com.ssafy.econimal.domain.user.entity.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Service
@RequiredArgsConstructor
@Slf4j
public class AuthEmailService {
private final BCryptPasswordEncoder encoder;
private final AuthValidator validator;
private final RedisTemplate<String, String> redisTemplate;
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final SecureRandom random = new SecureRandom();
private static final long EXPIRATION_TIME = 5; // 인증 코드의 만료 시간 (분)
// 이메일 - 인증코드 확인
public void verifyCode(EmailAuthRequest request) {
String authCode = redisTemplate.opsForValue().get(request.email());
validator.verifyAuthCode(request, authCode);
redisTemplate.delete(request.email());
}
// 6자리 무작위 인증코드 생성
public String generateVerificationCode() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 6; i++) {
int index = random.nextInt(CHARACTERS.length());
sb.append(CHARACTERS.charAt(index));
}
return sb.toString();
}
// 이메일, 암호 레디스 저장
public void saveVerificationCode(String email, String code) {
redisTemplate.opsForValue().set(email, code, Duration.ofMinutes(EXPIRATION_TIME));
}
// 비밀번호 일치 확인
public void updatePassword(UpdatePasswordRequest request) {
validator.verifyUpdatePassword(request.newPassword1(), request.newPassword2());
User findUser = validator.findUser(request.userId());
String encodedPassword = encoder.encode(request.newPassword1());
findUser.updatePassword(encodedPassword);
}
}