Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
Tags
- gradle
- 자바
- mysqlworkbench
- 스프링
- cloudtype
- 스프링예외처리
- 인텔리제이
- 스프링부트
- 소셜로그인
- 도커
- 깃허브
- 키오스크
- 그라파나
- 배포
- supabase
- 알고리즘
- AWS
- 잔디심기챌린지
- JWT
- 내일배움캠프
- tomcat
- 스프링시큐리티
- 테스트코드
- 연동
- java
- 백준
- 스파르타코딩클럽
- o'auth2
- 프로메테우스
- EC2
Archives
- Today
- Total
개발스토리지😃
[스프링] 회원가입 이메일 인증 구현(구글 이메일 사용) 본문
회원가입을 할 때 구글 이메일을 사용하여 사용자에게 인증번호를 보내고
사용자가 인증번호를 인증하면 회원가입이 가능하도록 구현했습니다.
1. 결과 화면
- 인증이 완료되지 않아 회원가입 불가

- 인증번호 전송

- 인증번호 확인

- 레디스에 아래와 같이 저장
- Key = EMAIL_CODE:<이메일>
- Value = 인증번호 코드

- 인증이 완료되면 Value값을 ture로 변환

- 회원가입 완료

2. 구글 이메일 연동
- GMail에 들어가 오른쪽 위에 설정 버튼을 눌러 모든 설정 보기를 클릭

- 번호 순서대로 설정한 후 변경사항 저장

- 구글 계정에 들어가 앱 비밀번호를 검색하여 클릭

- 비밀번호를 생성하면 16글자의 문자열을 받을 수 있음

3. MailAuthCodeRequest
- 메일 인증코드를 받기 위한 DTO
public record MailAuthCodeRequest(
@NotBlank(message = "이메일은 필수 입력값입니다.")
@Email(message = "올바른 이메일 형식이 아닙니다.")
String email
) {
}
4. MailAuthCodeVerifyRequest
- 전송받은 메일 인증코드를 검증하기 위한 DTO
public record MailAuthCodeVerifyRequest(
@NotBlank(message = "이메일은 필수 입력값입니다.")
@Email(message = "올바른 이메일 형식이 아닙니다.")
String email,
@NotBlank(message = "인증번호는 필수 입력값입니다.")
String code
) {
}
5. MailController
- 회원가입 시 이메일 인증 기능을 제공하는 컨트롤러
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/auth")
public class MailController {
private final MailService mailService;
/**
* 회원가입용 인증 코드 메일 발송
*/
@PostMapping("/send-code")
public ResponseEntity<Void> sendCode(@RequestBody @Valid MailAuthCodeRequest request) {
mailService.sendVerificationCode(request.email());
return ResponseEntity.ok().build();
}
/**
* 인증 코드 검증
*/
@PostMapping("/verify-code")
public ResponseEntity<Void> verifyCode(@RequestBody @Valid MailAuthCodeVerifyRequest request) {
mailService.verifyCode(request.email(), request.code());
return ResponseEntity.ok().build(); // 성공 시 200 OK (응답 바디 없음)
}
}
6. MailService
- 이메일 인증 코드를 발송하고, 해당 코드를 검증하여 사용자 이메일 인증 여부를 확인하는 서비스
@Slf4j
@Service("mailService")
@RequiredArgsConstructor
public class MailService {
private final JavaMailSender javaMailSender;
private final RedisRepository redisRepository;
/**
* 인증번호 메일 전송
*/
public void sendVerificationCode(String email) {
// 6자리 난수 생성
String code = String.valueOf((int) (Math.random() * 900000) + 100000);
// Redis에 3분간 유효한 인증 코드 저장
redisRepository.saveMailAuthCode(email, code, Duration.ofMinutes(3));
// HTML 본문 문자열 직접 작성
String html = String.format("""
<html>
<body style="font-family: Arial, sans-serif;">
<h2>회원가입 이메일 인증 코드</h2>
<p>아래 인증 코드를 입력해주세요:</p>
<p style="font-size: 24px; font-weight: bold;">%s</p>
<p>3분 이내에 입력하지 않으면 코드가 만료됩니다.</p>
</body>
</html>
""", code);
try {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(email);
helper.setSubject("회원가입 이메일 인증 코드");
helper.setText(html, true);
javaMailSender.send(message);
} catch (MessagingException e) {
log.error("이메일 발송 실패. 대상: {}, 원인: {}", email, e.getMessage(), e);
throw new BizException(MailErrorCode.SEND_FAILED);
}
}
/**
* 인증 코드 검증
*/
public void verifyCode(String email, String code) {
String storedCode = redisRepository.getMailAuthCode(email);
if (!storedCode.equals(code)) {
throw new BizException(MailErrorCode.CODE_NOT_MATCHED);
}
// 인증 성공 → 인증 상태 30분간 유지
redisRepository.save("EMAIL_VERIFIED:" + email, "true", Duration.ofMinutes(30));
// 인증 코드 삭제
redisRepository.deleteMailAuthCode(email);
}
}
7. RedisRepository
- 이메일 인증 코드 저장·검증 등 인증 관련 정보를 Redis를 활용해 관리
@Repository
@RequiredArgsConstructor
public class RedisRepository {
private final RedisTemplate<String,String> redisTemplate;
public void saveMailAuthCode(String email, String code, Duration ttl) {
redisTemplate.opsForValue().set("EMAIL_CODE:" + email, code, ttl);
}
public String getMailAuthCode(String email) {
String code = redisTemplate.opsForValue().get("EMAIL_CODE:" + email);
if (code == null) {
throw new BizException(MailErrorCode.EMAIL_CODE_NOT_FOUND);
}
return code;
}
public void deleteMailAuthCode(String email) {
redisTemplate.delete("EMAIL_CODE:" + email);
}
public void save(String key, String value, Duration ttl) {
try {
redisTemplate.opsForValue().set(key, value, ttl);
} catch (Exception e) {
throw new BizException(MailErrorCode.SEND_FAILED);
}
}
public boolean hasKey(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
public void delete(String key) {
redisTemplate.delete(key);
}
}
8. MailErrorCode
@Getter
@RequiredArgsConstructor
public enum MailErrorCode implements ErrorCode {
SEND_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "E001", "인증번호 발송에 실패했습니다."),
EMAIL_CODE_NOT_FOUND(HttpStatus.BAD_REQUEST, "E002", "이메일 인증 코드가 존재하지 않습니다. 인증번호 발송을 요청해주세요."),
CODE_NOT_MATCHED(HttpStatus.BAD_REQUEST, "E003", "이메일 인증 코드가 일치하지 않습니다."),
EMAIL_NOT_VERIFIED(HttpStatus.BAD_REQUEST, "E004", "이메일 인증이 완료되지 않았습니다.");
private final HttpStatus httpStatus;
private final String code;
private final String message;
@Override
public HttpStatus getStatus() {
return httpStatus;
}
@Override
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
9. SecurityConfig
- 스프링시큐리티 permitAll() 추가
"/api/auth/send-code"
"/api/auth/verify-code"
10. application.yml
- 환경변수는 .env파일로 관리
spring:
mail:
host: smtp.gmail.com
port: 587
username: ${EMAIL_ID}
password: ${EMAIL_PASSWORD}
properties:
mail:
smtp:
starttls:
enable: true
auth: true
'프레임워크 > 스프링' 카테고리의 다른 글
| [스프링] HandlerMapping: URL지휘자 (0) | 2025.09.11 |
|---|---|
| [스프링] JWT 시크릿키 변경주기 (0) | 2025.09.09 |
| [스프링] @GlobalExceptionHandler 스켈레톤 (2) 커스터마이징 (0) | 2025.07.01 |
| [스프링] @GlobalExceptionHandler 스켈레톤 (1) 기본 예외 핸들러 (0) | 2025.06.30 |
| [스프링] 휴면 계정 처리를 위한 전략과 그 구현 (4) 스프링 배치와 테스트 (1) | 2025.06.27 |