• 회원가입 이메일 인증

    • 인증메일 발송 JavaMailSender

    • 인증 토큰값 확인

@Profile("local") // 로컬일때 이 bean이 등록되도록
@Component
@Slf4j
public class ConsoleMailSender implements JavaMailSender {

    // 콘솔로 출력하는 형태로 임시로 구현. 추후 변경
    
    @Override
    public MimeMessage createMimeMessage() {
        return null;
    }

    @Override
    public MimeMessage createMimeMessage(InputStream inputStream) throws MailException {
        return null;
    }

    @Override
    public void send(MimeMessage mimeMessage) throws MailException {

    }

    @Override
    public void send(MimeMessage... mimeMessages) throws MailException {

    }

    @Override
    public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {

    }

    @Override
    public void send(MimeMessagePreparator... mimeMessagePreparators) throws MailException {

    }

    @Override
    public void send(SimpleMailMessage simpleMailMessage) throws MailException {
        log.info(simpleMailMessage.getText());
    }

    @Override
    public void send(SimpleMailMessage... simpleMailMessages) throws MailException {

    }
}

이메일 전송 기능을 위해 JavaMailSender 를 구현한다.

임의로 콘솔로 출력하는 형태로 작성하였으며, local에서만 실행되도록 한다.

@Slf4j 를 이용하여 발송시 로그를 확인 할 수 있도록 한다.

 

 

 

    // AccountController.java
    
    @PostMapping("/sign-up") //  JSR-303 Valid 검사
    public String signUpSubmit(@Valid SignUpForm signUpForm, Errors errors) {
        if (errors.hasErrors()) {
            return "account/sign-up"; //에러가 있으면 다시 폼으로
        }
        accountService.processNewAccount(signUpForm);

        return "redirect:/";
    }
@Service
@RequiredArgsConstructor
public class AccountService {

    private final AccountRepository accountRepository;
    private final JavaMailSender javaMailSender;
    private final PasswordEncoder passwordEncoder;

    @Transactional
    public void processNewAccount(SignUpForm signUpForm) {
        Account newAccount = saveNewAccount(signUpForm); // 새로운 Account 생성
        newAccount.generateEmailCheckToken(); // 이메일 체크 토큰 생성
        // saveNewAccount 후에 detached 상태가 되기 때문에 토큰값이 저장이 안됨
        // persist 상태 유지를 위해 @Transactional 을 붙여야 함

        sendSignUpConfirmEmail(newAccount); // 이메일 전송
    }

    private Account saveNewAccount(@Valid SignUpForm signUpForm) {
        Account account = Account.builder()
                .email(signUpForm.getEmail())
                .nickname(signUpForm.getNickname())
                .password(passwordEncoder.encode(signUpForm.getPassword()))
                .studyCreatedByWeb(true)
                .studyEnrollmentResultByWeb(true)
                .studyUpdatedByWeb(true)
                .build();
        return accountRepository.save(account);
    }

    private void sendSignUpConfirmEmail(Account newAccount) {
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setTo(newAccount.getEmail());
        mailMessage.setSubject("StudyNy, 회원 가입 인증");
        mailMessage.setText("/check-email-token?token=" + newAccount.getEmailCheckToken() +
                "&email=" + newAccount.getEmail());
        javaMailSender.send(mailMessage);
    }
}
    // Account.java
    
    public void generateEmailCheckToken() {
        this.emailCheckToken = UUID.randomUUID().toString(); // 랜덤 UUID 사용
    }

 

sign-up요청이 들어오면 새로운 Account 생성 후 이메일 체크 토큰값을 생성한다. 

UUID를 이용하여 랜덤한 토큰 값을 생성하였으며,  이 토큰값과 함께 이메일을 전송하게 된다.

 

saveNewAccount 후에 detached 상태가 되기 때문에 persist 상태 유지를 위해 @Transactional 를 붙여줘야 한다.

 

 

// AccountController.java
    
    // 인증메일 확인
    @GetMapping("/check-email-token")
    public String checkEmailToken(String token, String email, Model model) {
        Account account = accountRepository.findByEmail(email);
        String view = "account/checked-email";
        if (account == null) {
            model.addAttribute("error", "wrong.email");
            return view;
        }

        if (!account.getEmailCheckToken().equals(token)) {
            model.addAttribute("error", "wrong.token");
            return view;
        }

        account.completeSignUp();
/*        account.setEmailVerified(true); 리팩토링 - Account로 이동
        account.setJoinedAt(LocalDateTime.now()); */
        model.addAttribute("numberOfUser", accountRepository.count());
        model.addAttribute("nickname", account.getNickname());
        return view;
    }

인증메일 확인을 하는 요청도 구현한다. 토큰 값을 받아 디비에 저장되어 있는 토큰값과 같은지 확인한다.

 

 

 

 

github

+ Recent posts