Skip to content

[REFACTOR] MemberService 이메일 인증 로직 책임 재배치 #162

@ryuwldnjs

Description

@ryuwldnjs

배경

MemberService.sendEmailVerification()verifyAndChangeEmail()에서 인프라 관심사가 서비스 코드에 직접 풀어져 있음.

현재 위치 문제 상세
MemberService frontendUrl 직접 참조 프론트엔드 URL 구조를 백엔드 서비스가 알고 있음
MemberService jwtUtil 직접 사용 인증 토큰 생성을 member 서비스가 직접 수행
MemberService URL 조합 로직 frontendUrl + "/verify-email?token=" + token — 프레젠테이션 레이어 로직

문제점

  • 프론트 라우팅 변경 시 백엔드 서비스 수정 필요 (불필요한 결합)
  • MemberService가 인증 인프라 세부사항을 알고 있음

해결 방향

member/mail/ 패키지 내에서 책임을 세 컴포넌트로 분리하여, MemberService에서 인프라 의존을 완전히 제거.

최종 구조

member/mail/
├── EmailVerificationTokenProvider  ← 토큰 생성 + 검증 (JwtUtil 래핑)
├── EmailVerificationClaim          ← 토큰 파싱 결과 레코드 (memberId, newEmail)
└── EmailChangeMailBuilder          ← 메일 빌드 (tokenProvider + frontendUrl + TemplateEngine)
컴포넌트 책임
EmailVerificationTokenProvider JwtUtil을 래핑하여 이메일 인증 토큰 생성(createToken) 및 검증(parseToken)
EmailChangeMailBuilder tokenProvider로 토큰 생성 → frontendUrl과 조합 → Thymeleaf로 HTML 렌더링
MemberService 비즈니스 검증(중복 확인, 회원 존재) + 오케스트레이션만 수행

변경 전후 비교

sendEmailVerification() 변경 전:

String token = jwtUtil.createEmailVerificationToken(memberId, newEmail);
String verificationUrl = frontendUrl + "/verify-email?token=" + token;
mailSender.send(emailChangeMailBuilder.build(newEmail, verificationUrl));

변경 후:

mailSender.send(emailChangeMailBuilder.build(memberId, newEmail));

verifyAndChangeEmail() 변경 전:

jwtUtil.validateTokenOrThrow(token);
String tokenType = jwtUtil.getTokenType(token);
if (!JwtUtil.TOKEN_TYPE_EMAIL_VERIFICATION.equals(tokenType)) { ... }
Long memberId = jwtUtil.getIdFromToken(token);
String newEmail = jwtUtil.getEmailFromToken(token);

변경 후:

EmailVerificationClaim claim = emailVerificationTokenProvider.parseToken(token);

작업 항목

  • EmailVerificationTokenProvider 신설 — 토큰 생성/검증 책임 분리
  • EmailVerificationClaim 레코드 신설 — 토큰 파싱 결과
  • EmailChangeMailBuilder에 토큰 생성 + URL 조합 로직 이동
  • MemberService에서 jwtUtil, frontendUrl 의존 제거
  • 테스트 수정 — 기존에 이메일 인증 테스트 없어 해당 없음

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions