이제 Member 에 남은 api는 삭제, 로그인, 리프레시 토큰 발급, 비밀번호 찾기 인증번호 검증 후 이메일로전송
이렇게 남았다.
삭제랑 이메일관련은 쉽다.
로그인,리프레시 토큰 재발급 api는 JWT를 사용할것이다.
먼저 이번 포스팅에는 삭제와 이메일관련 api부터 구현해보자.
ㅇ Service - deleteMember
public void deleteMember(Long memberId) {
Member existMember = memberRepository.findById(memberId)
.orElseThrow(()-> new EntityNotFoundException("사용차를 찾을 수 없습니다."));
memberRepository.delete(existMember);
}
ㅇ Controller - deleteMember
@DeleteMapping("/{member-id}")
public ResponseEntity<?> deleteMember(@PathVariable("member-id") Long memberId) {
memberService.deleteMember(memberId);
return ResponseEntity.ok("회원삭제가 완료되었습니다.");
}
ㅇ 테스트
쉽다. 원래는 lastLoggedIn 해서 스케줄러를 돌려서 기준을 정하고 그 기준에 미달할만큼 로그인하지않았다면, 휴면회원처리를 하는게 맞다. 하지만 일단은 기능구현부터 해야해서 이렇게 간단히 구현했다. 다음으로 비밀번호 찾기 로직을 구현해보자.
먼저 비밀번호를 찾기위해 이메일인증을 다시해야한다. signup에서 사용했던 sendEmail을 재사용하면 된다.
ㅇ Service - sendEmail
public void sendEmail(String recipientEmail, String subject) throws MessagingException {
try {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(recipientEmail);
helper.setSubject(subject);
String randomKey = generateRandomKey(7);
// EmailConfirmRandomKey 저장
EmailConfirmRandomKey confirmRandomKey = EmailConfirmRandomKey.builder()
.email(recipientEmail)
.randomKey(randomKey)
.build();
emailConfirmRandomKeyRepository.save(confirmRandomKey);
// 이메일 템플릿 불러오기
String emailTemplate = getEmailTemplate(recipientEmail, randomKey);
helper.setText(emailTemplate, true);
javaMailSender.send(message);
System.out.println("Email Template: " + emailTemplate);
} catch (MessagingException e) {
// 예외 처리 로직 작성
e.printStackTrace(); // 예외 내용을 콘솔에 출력하거나 로깅할 수 있습니다.
// 예외 처리 후 필요한 작업 수행
}
}
이건 그대로 사용하면되고,
ㅇ Controller - findPw
@PostMapping("/password")
public ResponseEntity<?> findPw(@RequestBody MemberDto.PasswordFind requestBody) {
String subject = "비밀번호 찾기용 랜덤키를 발송합니다.";
try {
memberService.sendEmail(requestBody.getEmail(), subject);
return ResponseEntity.ok("이메일이 성공적으로 발송되었습니다.");
} catch (MessagingException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("이메일 발송에 실패했습니다.");
}
}
일단 제목만 바꿔서 보냈다.
메일본문을 바꾸려면 새로 HTML 파일을 만들어야하는데 귀찮아서 그냥 재사용했다.
ㅇ 테스트
잘 도착하는걸 볼 수 있다.
ㅇ Service - verifyAndSend
패스워드를 담아보내려면 다시 디코딩해야하는데 안된다고 한다. 그래서 임시 비밀번호를 생성해서 보내주기로 했다. 그리고 사용자가 패스워드변경을 할 수 있게 만들어줘야 했다.
일단 임시 비밀번호를 생성하는 메서드와, 인증번호를 검증하고 임시 비밀번호를 생성해서 이메일로 보내주는 서비스로직을 짜봤다.
앞에서 사용한 코드들을 짬뽕해서 사용한거다.
public void verifyAndSend(String randomKey, String email) {
//이메일 검증
EmailConfirmRandomKey emailConfirmRandomKey = emailConfirmRandomKeyRepository.findByEmail(email)
.orElseThrow(() -> new IllegalStateException("유효하지 않은 이메일입니다."));
String newRandomKey = emailConfirmRandomKey.getRandomKey();
//비밀번호 인증용랜덤키를 검증
if(!randomKey.equals(newRandomKey)){
throw new IllegalArgumentException("인증코드가 유효하지 않습니다.");
}
Optional<Member> existingMember = memberRepository.findByEmail(email);
//임시 비밀번호를 생성
String tempPw = generateTempPw(10);
if(existingMember.isPresent()){
Member member = existingMember.get();
//임시비밀번호를 인코딩
String encodedTempPw = passwordEncoder.encode(tempPw);
//인코딩한 임시비밀번호를 DB에 저장.
member.setPassword(encodedTempPw);
memberRepository.save(member);
try {
String subject = "[shopppingmall] 임시 비밀번호를 보내드립니다.";
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(member.getEmail());
helper.setSubject(subject);
// 이메일 템플릿 불러오기
String pwTemplate = getPasswordTemplate(member.getEmail(), tempPw);
helper.setText(pwTemplate, true);
javaMailSender.send(message);
System.out.println("Email Template: " + emailTemplate);
} catch (MessagingException e) {
e.printStackTrace();
}
}
//인증용랜덤키 삭제
emailConfirmRandomKeyRepository.deleteById(email);
}
public String generateTempPw(int keyLength) {
//특수기호까지 추가
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%";
StringBuilder randomKey = new StringBuilder();
SecureRandom secureRandom = new SecureRandom();
for (int i = 0; i < keyLength; i++) {
int randomIndex = secureRandom.nextInt(characters.length());
randomKey.append(characters.charAt(randomIndex));
}
return randomKey.toString();
}
//패스워드 템플릿
public String getPasswordTemplate(String recipientEmail, String tempPw) {
try {
// Create the Thymeleaf context and set variables
Context context = new Context();
context.setVariable("recipientEmail", recipientEmail);
context.setVariable("tempPw", tempPw);
// Process the email template using the template engine
String emailTemplate = templateEngine.process("pw_template", context);
return emailTemplate;
} catch (Exception e) {
throw new RuntimeException("Failed to process email template.", e);
}
}
ㅇ resources-pw_template.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title> 고객님의 임시 비밀번호를 보내드립니다.</title>
</head>
<body>
<h1>Welcome!</h1>
<p>밑의 비밀번호를 복사해서 로그인 후, 비밀번호 변경을 하세요.</p>
<p>임시 비밀번호: <span th:text="${tempPw}"></span></p>
</body>
</html>
Controller - confirmFindPw
@PostMapping("/confirm-pw")
public ResponseEntity<?> confirmFindPw(@RequestBody MemberDto.Verify requestBody) {
try{
memberService.verifyAndSend(requestBody.getRandomKey(), requestBody.getEmail());
return ResponseEntity.ok("이메일로 임시비밀번호를 전송했습니다.");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("인증 처리중 오류가 발생했습니다.");
}
}
ㅇ 테스트
겨우 했다. 다음 포스팅에는 JWT를 다루는 로그인, 리프레시토큰 재발급을 해보도록 하겠다.