ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Boot 시리즈 11편 – 이메일 인증 및 비밀번호 재설정: 실전 보안 흐름 구현 전략
    기술과 산업/언어 및 프레임워크 2025. 4. 25. 16:30
    728x90

    Spring Boot에서 이메일 인증과 비밀번호 재설정 흐름을 안전하게 구현하는 방법을 소개합니다. 인증 토큰 발급, 만료 처리, 보안 설계 전략까지 포함된 실전 가이드입니다.


    Spring Boot 시리즈 11편 – 이메일 인증 및 비밀번호 재설정: 실전 보안 흐름 구현 전략

    대부분의 서비스에서 이메일 인증은 신뢰 기반 사용자 확보를 위해,
    비밀번호 재설정은 보안 사고 예방을 위해 반드시 필요한 기능입니다.

    이번 글에서는 Spring Boot 기반으로 이메일 인증 및 비밀번호 재설정 기능을 보안성, 유지보수성, 사용자 경험까지 고려하여
    기획부터 구현까지 실무 수준으로 구성해보겠습니다.


    📌 1. 이메일 인증이 필요한 이유

    목적 설명

    가입 계정 유효성 검증 실사용자 확인 (가짜/스팸 방지)
    계정 활성화 조건 설정 이메일 인증 전 로그인 차단 가능
    비밀번호 재설정 시 본인 확인 이메일을 통해 본인만 접근 가능하도록 설정
    보안 사고 대응 인증 링크는 1회성 & 시간 제한으로 제한 필요

    🔄 2. 이메일 인증 흐름 설계

    [1] 회원가입 요청 → 이메일 발송
    [2] 사용자 메일함 → 인증 링크 클릭
    [3] 백엔드에서 토큰 검증 → 계정 활성화 처리
    

    ✅ 3. 인증 토큰 Entity 설계

    @Entity
    public class VerificationToken {
    
        @Id
        @GeneratedValue
        private Long id;
    
        private String token;
    
        private String userEmail;
    
        private LocalDateTime expiryDate;
    
        public static VerificationToken generate(String email) {
            return new VerificationToken(UUID.randomUUID().toString(), email, LocalDateTime.now().plusHours(1));
        }
    
        public boolean isExpired() {
            return LocalDateTime.now().isAfter(expiryDate);
        }
    }
    

    ✉️ 4. 이메일 발송 서비스

    1️⃣ 토큰 생성 + 이메일 전송

    @Service
    @RequiredArgsConstructor
    public class EmailVerificationService {
    
        private final VerificationTokenRepository tokenRepository;
        private final EmailSender emailSender;
    
        public void sendVerificationEmail(String email) {
            VerificationToken token = VerificationToken.generate(email);
            tokenRepository.save(token);
    
            String link = "https://myapp.com/api/auth/verify?token=" + token.getToken();
            String body = "이메일 인증을 완료하려면 아래 링크를 클릭하세요.\n" + link;
    
            emailSender.send(email, "회원가입 이메일 인증", body);
        }
    }
    

    2️⃣ 인증 완료 처리

    public void verifyToken(String token) {
        VerificationToken vt = tokenRepository.findByToken(token)
            .orElseThrow(() -> new BusinessException(ErrorCode.INVALID_TOKEN));
    
        if (vt.isExpired()) {
            throw new BusinessException(ErrorCode.EXPIRED_TOKEN);
        }
    
        User user = userRepository.findByEmail(vt.getUserEmail())
            .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
    
        user.activate();  // 계정 활성화
        userRepository.save(user);
        tokenRepository.delete(vt);  // 1회성 토큰 폐기
    }
    

    🔐 5. 비밀번호 재설정 흐름 설계

    [1] 사용자 이메일 입력 → 임시 토큰 생성 및 메일 발송
    [2] 메일의 링크 클릭 → 새로운 비밀번호 입력 폼
    [3] 토큰 검증 → 비밀번호 변경 처리
    

    🧱 6. 비밀번호 재설정 토큰 구조 (재사용 가능)

    @Entity
    public class PasswordResetToken {
    
        @Id @GeneratedValue
        private Long id;
    
        private String token;
    
        private String email;
    
        private LocalDateTime expiresAt;
    
        public static PasswordResetToken create(String email) {
            return new PasswordResetToken(UUID.randomUUID().toString(), email, LocalDateTime.now().plusMinutes(30));
        }
    
        public boolean isExpired() {
            return LocalDateTime.now().isAfter(expiresAt);
        }
    }
    

    🔁 7. 재설정 API 흐름 예시

    1️⃣ 메일 발송 API

    @PostMapping("/api/auth/reset-password-request")
    public ApiResponse<Void> requestPasswordReset(@RequestBody EmailRequest request) {
        passwordResetService.sendResetLink(request.getEmail());
        return ApiResponse.success();
    }
    

    2️⃣ 비밀번호 변경 API

    @PostMapping("/api/auth/reset-password")
    public ApiResponse<Void> resetPassword(@RequestBody ResetPasswordRequest request) {
        passwordResetService.resetPassword(request.getToken(), request.getNewPassword());
        return ApiResponse.success();
    }
    

    🧠 보안 고려 사항

    항목 권장 설계

    토큰 만료시간 30분 ~ 1시간 이내 제한
    링크 유효성 단일 사용 후 삭제 or 만료
    사용자 피드백 "링크가 만료되었습니다" 등의 UX 메시지 중요
    토큰 식별자 UUID + 이메일 등 혼합 전략 사용 가능
    이메일 전송 비밀번호는 절대 메일에 포함하지 말 것

    ✅ 마무리 요약

    항목 요약

    인증 흐름 이메일 → 링크 클릭 → 토큰 검증 → 계정 활성화
    토큰 설계 VerificationToken, PasswordResetToken 등 Entity 기반 관리
    메일 발송 이메일 전송은 비동기 or 별도 서비스로 분리 권장
    보안 설계 만료 시간, 1회성 제한, 예외 처리 통일
    UX 강화 사용자에게 명확한 안내 메시지와 흐름 제공

    📌 다음 편 예고

    Spring Boot 시리즈 12편: 파일 업로드 처리 전략 – 이미지, 문서 업로드부터 S3 연동까지 실전 가이드

     

    728x90
Designed by Tistory.