728x90

개요

멋사 파이널 프로젝트 중 회원가입 시 이메일 인증과 비밀번호 찾기 로직을 구현해보고자 한다.

회원가입에 성공 후 비밀번호를 잊어버렸을 시 코드 구현을 하고자 한다.

 

나의 환경

Window 11

intelliJ

java 21 

spring Boot 3.3.0

spring Security 6 

jwt 0.11.5

 

의존성 설치

// email smtp
implementation 'org.springframework.boot:spring-boot-starter-mail'

 

필요한 환경변수 세팅 Google SMTP

  • 비밀번호는 구글 이메일의 비밀번호가 아니라 구글 설정에서 앱 비밀번호를 생성받아야 한다.
  • 아래 링크에서 잘 설명해주셔서 참고!
spring:
  application:
    name: OMG_project
  mail:
    host: smtp.gmail.com
    port: 587
    username: {gmail email}
    password: {password}
    properties:
      mail:
        smtp:
          starttls:
            enable: true
          auth: true

[Go] Google Gmail SMTP 설정 방법 및 메일 전송 (tistory.com)

 

[Go] Google Gmail SMTP 설정 방법 및 메일 전송

■ SMTP 간이 우편 전송 프로토콜(Simple Mail Transfer Protocol)의 약자. 이메일 전송에 사용되는 네트워크 프로토콜이다. 인터넷에서 메일 전송에 사용되는 표준이다. 1982년 RFC821에서 표준화되어 현재

hyunmin1906.tistory.com

 

 

1. dto

@Getter @Setter
public class MailRequest {

    private String mail;
}
@Getter @Setter
public class PasswordVerificationRequest {

    private String mail;
    private String tempPassword;
}
  • 사실 역할로 봤을 때는 dto의 기능을 하지 않기 때문에 dto라 명명한 것이 잘못되었지만... 나중에 수정하는 것으로 하고 넘어갔다.

 

2. Service

public interface MailService {

    String createTemporaryPassword(String email);

    boolean verifyTemporaryPassword(String email, String tempPassword);

    void sendTemporaryPasswordMail(String email, String tempPassword);
}
@Service
@RequiredArgsConstructor
@Slf4j
public class MailServiceImpl implements MailService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JavaMailSender javaMailSender;
    private static final String senderEmail = "ch9800113@gmail.com";
    private static final Map<String, Integer> verificationCodes = new HashMap<>();

    /**
     * 임시 비밀번호 자동 생성 메서드
     */
    private static String generateRandomPassword() {
        int length = 8;
        StringBuilder sb = new StringBuilder(length);
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append((char) (random.nextInt(10) + '0'));
        }
        return sb.toString();
    }

    /**
     * 임시 비밀번호 전송
     */
    @Override
    public void sendTemporaryPasswordMail(String mail, String tempPassword) {
        MimeMessage message = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
            helper.setFrom(senderEmail);
            helper.setTo(mail);
            helper.setSubject("OMG 임시 비밀번호");
            String body = "<h2>OMG에 오신걸 환영합니다!</h2><p>아래의 임시 비밀번호를 사용하세요.</p><h1>" + tempPassword + "</h1><h3>반드시 비밀번호를 재설정하세요.</h3>";
            helper.setText(body, true);
            javaMailSender.send(message);
        } catch (MessagingException e) {
            throw new RuntimeException("임시 비밀번호 전송 오류", e);
        }
    }

    /**
     * 임시 비밀번호 생성 및 DB 업데이트
     */
    @Override
    public String createTemporaryPassword(String mail) {
        String tempPassword = generateRandomPassword();
        User user = userRepository.findByUsername(mail)
                .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다."));
        user.setPassword(passwordEncoder.encode(tempPassword));
        userRepository.save(user);
        return tempPassword;
    }

    /**
     * 임시 비밀번호 검증
     */
    @Override
    public boolean verifyTemporaryPassword(String mail, String tempPassword) {
        User user = userRepository.findByUsername(mail)
                .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다."));
        return passwordEncoder.matches(tempPassword, user.getPassword());
    }
}

 

 

[ 코드 설명 ]

/**
 * 임시 비밀번호 자동 생성 메서드
 */
private static String generateRandomPassword() {
    int length = 8;
    StringBuilder sb = new StringBuilder(length);
    Random random = new Random();
    for (int i = 0; i < length; i++) {
        sb.append((char) (random.nextInt(10) + '0'));
    }
    return sb.toString();
}
  • 반환 값: String (문자열)
  • 생성 방식: 이 메서드는 8자리의 숫자로 구성된 문자열을 생성하는 메서드이다.
    • 문자열은 StringBuilder를 사용하여 효율적으로 생성되도록 구현했다.
    • 각 반복에서 random.nextInt(10) + '0'을 통해 0부터 9까지의 숫자를 문자로 변환하여 문자열에 추가한다.
  • StringBuilder 사용이유 ::
    • String은 불변 객체(immutable object)이다. 즉 한 번 생성된 String은 변경할 수 없으며, 문자열의 조작은 새로운 String 객체를 생성하여 처리된다.
    • StringBuilder를 사용하여 문자열을 생성한 후, 최종적으로 toString() 메서드를 호출하여 불변의 String 객체를 반환하도록 구현했다.
    • 위의 코드는 숫자로만 구성했지만, 나중에 보안을 위해 아래처럼 작성하는 것으로 바꾸었다.
  •  
private static String generateRandomPassword() {
    int length = 8;
    StringBuilder sb = new StringBuilder(length);
    Random random = new Random();
    String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (int i = 0; i < length; i++) {
        sb.append(characters.charAt(random.nextInt(characters.length())));
    }

    return sb.toString();
}
/**
 * 임시 비밀번호 전송
 */
@Override
public void sendTemporaryPasswordMail(String mail, String tempPassword) {
    MimeMessage message = javaMailSender.createMimeMessage();
    try {
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        helper.setFrom(senderEmail);
        helper.setTo(mail);
        helper.setSubject("임시 비밀번호");
        String body = "<h2>000에 오신걸 환영합니다!</h2><p>아래의 임시 비밀번호를 사용하세요.</p><h1>" + tempPassword + "</h1><h3>반드시 비밀번호를 재설정하세요.</h3>";
        helper.setText(body, true);
        javaMailSender.send(message);
    } catch (MessagingException e) {
        throw new RuntimeException("임시 비밀번호 전송 오류", e);
    }
}
  • 반환 값: void
  •  생성 방식 : 이 메서드는 임시비밀번호를 이메일로 전송하는 기능만 수행하고, 결과를 반환할 필요가 없다
    • javaMailSender.send(message); 를 통해 메서드에서 바로 구현하여 바로 메일을 전송하였다.
  • 하지만 저번 포스트에서 회원가입시 이메일 인증 번호 전송 로직을 보면
@Override
public MimeMessage createMail(String mail){
    createNumber(mail);
    MimeMessage message = javaMailSender.createMimeMessage();

    try {
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        helper.setFrom(senderEmail);
        helper.setTo(mail);
        helper.setSubject("이메일 인증번호");
        String body = "<h2>000에 오신걸 환영합니다!</h2><h3>아래의 인증번호를 입력하세요.</h3><h1>" + verificationCodes.get(mail) + "</h1><h3>감사합니다.</h3>";
        helper.setText(body, true);
    } catch (MessagingException e) {
        e.printStackTrace();
    }

    return message;
}

/**
 * createMail() 메서드의 내용을 이메일 전송
 */
@Async
@Override
public CompletableFuture<Integer> sendMail(String mail) {
    MimeMessage message = createMail(mail);
    javaMailSender.send(message);
    return CompletableFuture.completedFuture(verificationCodes.get(mail));
}
  • 여기서 코드의 반환값은 MimeMessage 이다.
  • 즉 javaMailSender.send(message); 를 하지 않았기 때문에 따로 sendMail 메서드를 통해 이메일 전송을 해줘야 한다.
  • MimeMessage  란? ::
    • MimeMessage  객체는 이메일 메시지를 생성하고 설정하는 데 사용되는 객체이다.
    • 발신자, 수신자, 제목, 본문 내용, 첨부 파일 등 이메일의 모든 구성 요소를 설정할 수 있고 설정된 MimeMessage 객체는 JavaMailSender를 통해 이메일 서버로 전송해야 한다.
  • 나중에 코드 통일성을 위해 하나의 메서드에서 전송될 수 있도록 구현할 예정이다.

 

 

3. Controller

@RestController
@RequiredArgsConstructor
@EnableAsync
public class MailApiController {

    private final MailService mailService;
    private final UserService userService;

    /**
     * 임시 비밀번호 재발급 발송 메서드
     */
    @PostMapping("/api/users/reset-password")
    public ResponseEntity<String> resetPassword(@RequestBody MailRequest mailRequest) {
        String email = mailRequest.getMail();

        if (userService.existsByUsername(email)) {
            String tempPassword = mailService.createTemporaryPassword(email);
            mailService.sendTemporaryPasswordMail(email, tempPassword);
            return ResponseEntity.ok("임시 비밀번호가 이메일로 발송되었습니다.");
        } else {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("해당 이메일로 가입된 사용자가 없습니다.");
        }
    }

    /**
     * 임시 비밀번호 검증 메소드
     */
    @PostMapping("/api/users/verify-temporary-password")
    public ResponseEntity<String> verifyTemporaryPassword(@RequestBody PasswordVerificationRequest request) {
        boolean isVerified = mailService.verifyTemporaryPassword(request.getMail(), request.getTempPassword());
        return isVerified ? ResponseEntity.ok("Verified") : ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Verification failed");
    }
}
/**
 * 비밀번호 재발급 페이지 이동
 */
@GetMapping("/users/reset-user-password")
public String showResetPasswordForm() {
    return "/user/findPassword";
}

 

 

4. 프론트엔드

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>비밀번호 재발급</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <link rel="stylesheet" href="/css/find-password.css">
</head>
<body>
<form id="emailVerificationForm">

    <h1>비밀번호 재발급</h1>
    <label for="email">가입 이메일</label>
    <input type="email" id="email" name="email" placeholder="Email" required/>
    <button type="button" id="send-code-button">임시 비밀번호 발송</button>
    <span id="emailCheckMessage" class="error"></span>

    <div id="verifyCodeSection">
        <label for="temporaryPassword">임시 비밀번호</label>
        <input type="text" id="temporaryPassword" name="temporaryPassword" placeholder="임시 비밀번호 입력" required />
        <button type="button" id="verify-temporary-password-button">임시 비밀번호 확인</button>
        <span id="verificationMessage" class="error"></span>
    </div>
</form>
<script>
    $(document).ready(function() {
        $('#verifyCodeSection').hide();

        $('#send-code-button').on('click', function() {
            let email = $('#email').val();
            $.ajax({ // 이메일이 데이터베이스에 있는지 확인
                url: '/api/users/check-email',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify({ mail: email }),
                success: function(response) {
                    if (response) {
                        $.ajax({ // 이메일이 존재하면 임시 비밀번호 발송
                            url: '/api/users/reset-password',
                            type: 'POST',
                            contentType: 'application/json',
                            data: JSON.stringify({ mail: email }),
                            success: function(response) {
                                $('#verifyCodeSection').slideDown(); // 인증 코드 입력 섹션 표시
                                alert('임시 비밀번호가 이메일로 발송되었습니다. 이메일을 확인해주세요.');
                            },
                            error: function(error) {
                                alert('임시 비밀번호 발송에 실패했습니다. 다시 시도해주세요.');
                            }
                        });
                    } else {
                        $('#emailCheckMessage').text('해당 이메일로 가입된 사용자가 없습니다.').show();
                    }
                },
                error: function(error) {
                    alert('이메일 확인 중 오류가 발생했습니다. 다시 시도해주세요.');
                }
            });
        });

        $('#verify-temporary-password-button').on('click', function() {
            const email = $('#email').val();
            const tempPassword = $('#temporaryPassword').val();
            $.ajax({
                url: '/api/users/verify-temporary-password',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify({ mail: email, tempPassword: tempPassword }),
                success: function(response) {
                    if (response === "Verified") {
                        alert("임시 비밀번호가 확인되었습니다. 로그인하세요.");
                        window.location.href = "/signin";
                    } else {
                        $('#verificationMessage').text("임시 비밀번호가 일치하지 않습니다. 다시 시도하세요.").show();
                    }
                },
                error: function(xhr, status, error) {
                    alert("임시 비밀번호 검증에 실패했습니다. 다시 시도하세요.");
                }
            });
        });
    });
</script>
</body>
</html>
  1. 해당 이메일이 디비에 있는지 확인한다.
  2. 이메일이 존재한다면 해당 이메일로 임시 비밀번호를 전송해준다.
  3. 이때 폼에서는 숨겼던 섹션을 표시하고 임시비밀번호를 입력 란을 활성화한다.
  4. 임시비밀번호가 이메일로 전송한 값과 같은지 확인한다.
  5. 이때 임시비밀번호가 디비에 업데이트가 되어서 기존 비밀번호로 인증을 할 수 없게 된다.

 

여기까지 끝-!

 

 

 

 

 


jQuery에서 HTML 요소를 표시하는 두 가지 방법

 

  • jQuery 에서 아래의 두가지가 섹션을 보여주는 방식의 차이라서 정리한다.
// 애니메이션 효과로 서서히 표시
$('#verifyCodeSection').slideDown();

// 즉시 표시
$('#verifyCodeSection').show();

 

 

 

728x90
728x90

개요

멋사 파이널 프로젝트 중 회원가입 시 이메일 인증과 비밀번호 찾기 로직을 구현해보고자 한다.

회원가입 시 받는 이메일 인증은 사용자 식별 및 보안 강화를 위해 필요한 기술이다. 만약 이메일 인증과 같은 인증 기술이 없다면 한 사람이 10개 혹은 1000개의 계정을 무한대로 생성할 수 있다는 것인데, 이는 스팸이나 부정 사용 등 서비스 품질을 하락시킬 수 있다. 이메일 인증과 관련해서 구현하기까지 수많은 구글링과 시행착오가 있어서 정리해놓을려고 한다.

 

나의 환경

Window 11

intelliJ

java 21 

spring Boot 3.3.0

spring Security 6 

jwt 0.11.5

 

의존성 설치

// email smtp
implementation 'org.springframework.boot:spring-boot-starter-mail'

 

필요한 환경변수 세팅 Google SMTP

  • 비밀번호는 구글 이메일의 비밀번호가 아니라 구글 설정에서 앱 비밀번호를 생성받아야 한다.
  • 아래 링크에서 잘 설명해주셔서 참고!
spring:
  application:
    name: OMG_project
  mail:
    host: smtp.gmail.com
    port: 587
    username: {gmail email}
    password: {password}
    properties:
      mail:
        smtp:
          starttls:
            enable: true
          auth: true

[Go] Google Gmail SMTP 설정 방법 및 메일 전송 (tistory.com)

 

[Go] Google Gmail SMTP 설정 방법 및 메일 전송

■ SMTP 간이 우편 전송 프로토콜(Simple Mail Transfer Protocol)의 약자. 이메일 전송에 사용되는 네트워크 프로토콜이다. 인터넷에서 메일 전송에 사용되는 표준이다. 1982년 RFC821에서 표준화되어 현재

hyunmin1906.tistory.com

 

 

 

1. dto

이메일 인증에 필요한 dto 를 작성한다.

@Getter @Setter
public class MailRequest {

    private String mail;
}
@Getter @Setter
public class MailVerificationRequest {

    private String mail;
    private int code;
}
  • 사실 역할로 봤을 때는 dto의 기능을 하지 않기 때문에 dto라 명명한 것이 잘못되었지만... 나중에 수정하는 것으로 하고 넘어갔다.

 

 

2. Service

  • 구현하고자 하는 기능에 맞게 코드를 짠다.
public interface MailService {

    MimeMessage createMail(String mail);

    boolean verifyCode(String email, int code);

    CompletableFuture<Integer> sendMail(String mail);
}
@Service
@RequiredArgsConstructor
@Slf4j
public class MailServiceImpl implements MailService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JavaMailSender javaMailSender;
    private static final String senderEmail = "메일을 보낼 구글 이메일";
    private static final Map<String, Integer> verificationCodes = new HashMap<>();

    /**
     * 인증 코드 자동 생성 메서드
     */
    public static void createNumber(String email){
        int number = new Random().nextInt(900000) + 100000; // 100000-999999 사이의 숫자 생성
        verificationCodes.put(email, number);
    }

    /**
     * 이메일 전송
     */
    @Override
    public MimeMessage createMail(String mail){
        createNumber(mail);
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
            helper.setFrom(senderEmail);
            helper.setTo(mail);
            helper.setSubject("이메일 인증번호");
            String body = "<h2>000에 오신걸 환영합니다!</h2><h3>아래의 인증번호를 입력하세요.</h3><h1>" + verificationCodes.get(mail) + "</h1><h3>감사합니다.</h3>";
            helper.setText(body, true);
        } catch (MessagingException e) {
            e.printStackTrace();
        }

        return message;
    }

    /**
     * createMail() 메서드의 내용을 이메일 전송
     */
    @Async
    @Override
    public CompletableFuture<Integer> sendMail(String mail) {
        MimeMessage message = createMail(mail);
        javaMailSender.send(message);
        return CompletableFuture.completedFuture(verificationCodes.get(mail));
    }

    /**
     * 이메일 인증 코드 검증
     */
    @Override
    public boolean verifyCode(String mail, int code) {
        Integer storedCode = verificationCodes.get(mail);
        return storedCode != null && storedCode == code;
    }
}

1) 주어진 이메일 주소에 대해 6자리 인증 코드를 생성하고 verificationCodes 맵에 저장한다.
{이메일 : 인증코드} 형태로 저장될 것이다.

2) 입력한 이메일 주소로 발송할 이메일 메시지를 작성한다.

3) 2에서 생성한 이메일 메시지를 비동기적으로 발송한다.

4) 사용자가 입력한 인증코드와 실제 발송된 인증코드와 일치하는지 확인한다.

 

 

 

3. Controller

@RestController
@RequiredArgsConstructor
@EnableAsync
public class MailApiController {

    private final MailService mailService;
    private final UserService userService;

    /**
     * 인증번호 발송 메소드
     */
    @PostMapping("/api/users/mail")
    public CompletableFuture<String> mailSend(@RequestBody MailRequest mailRequest) {
        return mailService.sendMail(mailRequest.getMail())
                .thenApply(number -> String.valueOf(number));
    }

    /**
     * 인증번호 검증 메소드
     */
    @PostMapping("/api/users/verify-code")
    public String verifyCode(@RequestBody MailVerificationRequest verificationRequest) {
        boolean isVerified = mailService.verifyCode(verificationRequest.getMail(), verificationRequest.getCode());
        return isVerified ? "Verified" : "Verification failed";
    }
}
  • 해당 앤드포인트로 요청이 들어오면 해당 요청을 수행한다.

 

4. 프론트엔드

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>회원가입</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <link rel="stylesheet" href="/css/signup.css">
</head>
<body>
<form id="signup-form" action="/signup" method="post">
    <h1>회원가입</h1>
    <hr/>

    <div th:if="${error}" class="error-message">
        <p th:text="${error}"></p>
    </div>

    <label for="email">이메일</label>
    <input type="email" id="email" name="username" placeholder="이메일 입력" required/>
    <button type="button" id="check-email-button" class="light-button">중복확인</button>
    <span id="emailCheckMessage" class="error"></span>

    <button type="button" id="send-code-button" class="light-button" style="display: none;">인증 코드 발송</button>

    <div id="verifyCodeSection">
        <label for="verificationCode">인증 코드</label>
        <input type="text" id="verificationCode" name="verificationCode" placeholder="인증번호 입력" required/>
        <button type="button" id="verify-code-button" class="light-button">이메일 인증</button>
        <span id="verificationMessage" class="error"></span>
    </div>

    <button type="submit" id="signup-button" disabled>회원가입</button>
</form>
<script src="/js/signup.js"></script>
</body>
</html>
$(document).ready(function() {
    function validateForm() {
        let isValid = true;

        // 이메일, 닉네임 중복 및 비밀번호 일치 여부 검사
        if ($('#emailCheckMessage').hasClass('error')) {
            isValid = false;
        }
        $('#signup-button').prop('disabled', !isValid);
        return isValid;
    }

    // 이메일 중복 검사
    // 1. 이메일 중복되면 인증 메일 보내기 버튼은 숨김
    // 2. 이메일 중복이 없다면 인증 메일 보내기 버튼 활성화 됨
    $('#check-email-button').on('click', function() {
        let email = $('#email').val();

        $.ajax({
            type: 'POST',
            url: '/api/users/check-email',
            contentType: 'application/json',
            data: JSON.stringify({ mail: email }),
            success: function(response) {
                if (response) {
                    $('#emailCheckMessage').text("아이디가 이미 존재합니다.").removeClass('success').addClass('error');
                    $('#send-code-button').hide();  
                } else {
                    $('#emailCheckMessage').text("사용 가능한 아이디입니다.").removeClass('error').addClass('success');
                    $('#send-code-button').show();  
                }
                validateForm();
            },
            error: function(error) {
                $('#emailCheckMessage').text('이메일 확인 중 오류가 발생했습니다. 다시 시도해주세요.').removeClass('success').addClass('error');
                $('#send-code-button').hide();  
                validateForm();
            }
        });
    });

    // 인증 메일
    $('#send-code-button').on('click', function() {
        let email = $('#email').val();

        $.ajax({
            type: 'POST',
            url: '/api/users/mail',
            contentType: 'application/json',
            data: JSON.stringify({ mail: email }),
            success: function(response) {
                $('#verifyCodeSection').show(); 
                alert('인증 메일이 발송되었습니다. 인증 번호를 확인해주세요.');
            },
            error: function(error) {
                alert('메일 발송에 실패했습니다. 다시 시도해주세요.');
            }
        });
    });

    // 인증 코드 확인
    $('#verify-code-button').on('click', function() {
        let email = $('#email').val();
        let code = $('#verificationCode').val();

        $.ajax({
            type: 'POST',
            url: '/api/users/verify-code',
            contentType: 'application/json',
            data: JSON.stringify({ mail: email, code: code }),
            success: function(response) {
                if (response === 'Verified') {
                    $('#verificationMessage').text('인증 성공').removeClass('error').addClass('success');
                } else {
                    $('#verificationMessage').text('인증 실패. 올바른 코드를 입력하세요.').removeClass('success').addClass('error');
                }
            },
            error: function(error) {
                $('#verificationMessage').text('인증 실패. 다시 시도해주세요.').removeClass('success').addClass('error');
            }
        });
    });

    // 인증 코드 발송 버튼 --> 초기 상태에서는 비활성화
    $('#send-code-button').hide();

    // 인증 코드 입력 란 숨기기
    $('#verifyCodeSection').hide();
});
  • 사실 HTML 폼에서 닉네임, 연락처, 생년월일 등 적는 란이 있지만 이메일 인증에 필요한 코드만 남겨두었다.
  1. 이메일이 중복되어 있는지 확인한다. 이 부분은 위에 자바 코드에는 없다.
  2. 이메일이 중복되지 않았다면 해당 이메일로 인증번호를 보낸다.
  3. 인증번호 발송 버튼이 활성화된다. 
// 이메일 중복 검사
    // 1. 이메일 중복되면 인증 메일 보내기 버튼은 숨김
    // 2. 이메일 중복이 없다면 인증 메일 보내기 버튼 활성화 됨
    $('#check-email-button').on('click', function() {
        let email = $('#email').val();

        $.ajax({
            type: 'POST',
            url: '/api/users/check-email',
            contentType: 'application/json',
            data: JSON.stringify({ mail: email }),
            success: function(response) {
                if (response) {
                    $('#emailCheckMessage').text("아이디가 이미 존재합니다.").removeClass('success').addClass('error');
                    $('#send-code-button').hide();  // 오류가 있으면 인증 코드 발송 버튼 숨김
                } else {
                    $('#emailCheckMessage').text("사용 가능한 아이디입니다.").removeClass('error').addClass('success');
                    $('#send-code-button').show();  // 이메일 체크 통과 시 버튼 표시
                }
                validateForm();
            },
            error: function(error) {
                $('#emailCheckMessage').text('이메일 확인 중 오류가 발생했습니다. 다시 시도해주세요.').removeClass('success').addClass('error');
                $('#send-code-button').hide();  // 오류가 있으면 인증 코드 발송 버튼 숨김
                validateForm();
            }
        });
    });

4) 인증코드 입력 섹션이 활성화된다.

// 인증 메일
    $('#send-code-button').on('click', function() {
        let email = $('#email').val();

        $.ajax({
            type: 'POST',
            url: '/api/users/mail',
            contentType: 'application/json',
            data: JSON.stringify({ mail: email }),
            success: function(response) {
                $('#verifyCodeSection').show(); // 인증 코드 입력 섹션 표시
                alert('인증 메일이 발송되었습니다. 인증 번호를 확인해주세요.');
            },
            error: function(error) {
                alert('메일 발송에 실패했습니다. 다시 시도해주세요.');
            }
        });
    });

5) 해당 이메일과 입력한 코드를 /api/users/verify-code 앤드포인트에서 수행한다.

$('#verify-code-button').on('click', function() {
    let email = $('#email').val();
    let code = $('#verificationCode').val();

    $.ajax({
        type: 'POST',
        url: '/api/users/verify-code',
        contentType: 'application/json',
        data: JSON.stringify({ mail: email, code: code }),
        success: function(response) {
            if (response === 'Verified') {
                $('#verificationMessage').text('인증 성공').removeClass('error').addClass('success');
            } else {
                $('#verificationMessage').text('인증 실패. 올바른 코드를 입력하세요.').removeClass('success').addClass('error');
            }
        },
        error: function(error) {
            $('#verificationMessage').text('인증 실패. 다시 시도해주세요.').removeClass('success').addClass('error');
        }
    });
});

 

 

 

5. 결과

 

위에처럼 작성 후 실행하면

해당 이메일로 인증 번호가 전송된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

다음 편은 비밀번호 찾기 로직을 정리할 것이다.

728x90

+ Recent posts