Develop/Java

[Java] 이메일 인증 기반 회원가입 API 구현하기

DevPi 2024. 9. 3. 15:43
반응형

이번 포스트에서는 스프링 부트를 활용하여 회원가입 시 이메일 인증을 요구하는 API를 구현하는 방법을 설명합니다. 사용자에게 인증 이메일을 전송하고, 이메일에 포함된 버튼을 클릭해야만 회원가입이 완료되는 구조입니다. 이 과정에서는 이메일 템플릿을 Thymeleaf로 구성하며, 인증 정보는 데이터베이스(DB)에 저장합니다.


1. Gradle 설정

이메일 인증 API를 구현하기 위해 먼저 필요한 의존성을 build.gradle 파일에 추가합니다. 아래 코드를 참고하여 의존성을 설정합니다.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-mail'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}

 

2. application.yml 설정

SMTP 서버와 데이터베이스 설정을 application.yml 파일에 추가합니다. 아래 설정은 Gmail의 SMTP 서버를 사용하도록 구성되어 있습니다.

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password:
    h2:
      console:
        enabled: true
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  mail:
    host: smtp.gmail.com
    port: 587
    username: your-email@gmail.com
    password: your-email-password
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

여기서 spring.mail.username과 spring.mail.password는 실제 Gmail 계정 정보로 변경해야 합니다. Gmail의 경우 보안을 위해 앱 비밀번호를 생성하여 사용하는 것이 좋습니다.

 

3. 이메일 서비스 및 인증 메일 전송

3.1 이메일 템플릿 설정

이메일 템플릿을 만들기 위해 src/main/resources/templates 폴더에 verification-email.html 파일을 생성합니다. 이 템플릿은 이메일 본문에 포함될 인증 버튼을 구성합니다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>이메일 인증</title>
</head>
<body>
    <h3>이메일 인증</h3>
    <p>아래 버튼을 클릭하여 이메일 인증을 완료해 주세요:</p>
    <a th:href="@{${verificationUrl}}" style="display:inline-block;padding:10px 20px;color:white;background-color:blue;text-decoration:none;">이메일 인증</a>
</body>
</html>

 

3.2 이메일 서비스 클래스 작성

이메일 전송을 담당하는 EmailService 클래스를 작성합니다. 이 클래스는 사용자의 이메일로 인증 링크가 포함된 이메일을 전송하는 기능을 구현합니다.

@Service
public class EmailService {

    @Autowired
    private JavaMailSender mailSender;

    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    private VerificationTokenRepository tokenRepository;

    public void sendVerificationEmail(User user, String siteURL) throws MessagingException {
        String token = UUID.randomUUID().toString();
        createVerificationToken(user, token);

        String recipientAddress = user.getEmail();
        String subject = "이메일 인증 요청";
        String verificationUrl = siteURL + "/api/verify?token=" + token;

        Context context = new Context();
        context.setVariable("verificationUrl", verificationUrl);
        String htmlContent = templateEngine.process("verification-email", context);

        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setTo(recipientAddress);
        helper.setSubject(subject);
        helper.setText(htmlContent, true);

        mailSender.send(message);
    }

    private void createVerificationToken(User user, String token) {
        VerificationToken verificationToken = new VerificationToken();
        verificationToken.setToken(token);
        verificationToken.setUser(user);
        verificationToken.setExpiryDate(LocalDateTime.now().plusHours(24)); // 24시간 유효
        tokenRepository.save(verificationToken);
    }
}

이 서비스 클래스는 사용자에게 인증 이메일을 전송하고, 인증 토큰을 데이터베이스에 저장합니다. 인증 토큰은 만료 시간을 설정하여 일정 시간이 지나면 사용할 수 없도록 합니다.

 

4. 컨트롤러 및 인증 처리 로직

4.1 회원가입 및 인증 이메일 전송

회원가입 시 이메일 인증을 위해 사용자 정보를 저장하고 인증 이메일을 전송하는 로직을 UserController에서 구현합니다.

@RestController
@RequestMapping("/api")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private EmailService emailService;

    @PostMapping("/register")
    public String registerUser(@Valid @RequestBody User user) throws MessagingException {
        userRepository.save(user);
        String siteURL = ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
        emailService.sendVerificationEmail(user, siteURL);
        return "회원가입이 완료되었습니다. 이메일을 확인하여 인증을 완료해 주세요.";
    }

    @GetMapping("/verify")
    public String verifyUser(@RequestParam("token") String token) {
        return emailService.verifyUser(token);
    }
}

/register 엔드포인트는 사용자의 회원가입을 처리하고 인증 이메일을 전송합니다. /verify 엔드포인트는 인증 토큰을 검증하고 회원가입을 완료하는 기능을 수행합니다.

 

4.2 인증 처리 서비스 메서드

EmailService에 인증 토큰 검증 로직을 추가하여 사용자가 이메일을 통해 인증을 완료할 수 있도록 합니다.

public String verifyUser(String token) {
    VerificationToken verificationToken = tokenRepository.findByToken(token)
            .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 토큰입니다."));

    User user = verificationToken.getUser();
    if (verificationToken.getExpiryDate().isBefore(LocalDateTime.now())) {
        return "토큰이 만료되었습니다.";
    }

    user.setEnabled(true);
    userRepository.save(user);
    tokenRepository.delete(verificationToken);  // 토큰 삭제

    return "이메일 인증이 완료되었습니다!";
}

이 메서드는 인증 토큰을 검증하고, 사용자가 해당 토큰으로 인증을 완료했음을 기록합니다. 만료된 토큰은 사용할 수 없도록 설정하여 보안을 강화합니다.

 

5. 실행 및 테스트

모든 설정이 완료되었으므로 애플리케이션을 실행하고 Postman이나 브라우저를 통해 API를 테스트할 수 있습니다.

  • 회원가입 요청 URL: POST http://localhost:8080/api/register
  • 파라미터: JSON 형식의 사용자 정보 (이메일, 비밀번호)

회원가입 후 전송된 이메일을 확인하고, 인증 링크를 클릭하면 회원가입이 완료됩니다.


이 포스트를 통해 스프링 부트를 사용한 이메일 인증 기반의 회원가입 API를 구현하는 방법을 살펴보았습니다. 추가적으로 보안 설정을 강화하거나 예외 처리를 추가하여 완성도를 높일 수 있습니다.

반응형