Skip to content

Commit 4388712

Browse files
committed
Feat: 비밀번호 재설정 요청 API 구현
1 parent 6c1d623 commit 4388712

File tree

4 files changed

+69
-0
lines changed

4 files changed

+69
-0
lines changed

src/main/java/com/back/domain/user/controller/AuthController.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public ResponseEntity<RsData<Map<String, String>>> refreshToken(
100100
));
101101
}
102102

103+
// 아이디 찾기
103104
@PostMapping("/username/recover")
104105
public ResponseEntity<RsData<Void>> recoverUsername(
105106
@Valid @RequestBody sendEmailRequest request
@@ -111,4 +112,17 @@ public ResponseEntity<RsData<Void>> recoverUsername(
111112
null
112113
));
113114
}
115+
116+
// 비밀번호 재설정 요청
117+
@PostMapping("/password/recover")
118+
public ResponseEntity<RsData<Void>> recoverPassword(
119+
@Valid @RequestBody sendEmailRequest request
120+
) {
121+
authService.recoverPassword(request.email());
122+
return ResponseEntity
123+
.ok(RsData.success(
124+
"비밀번호 재설정 링크를 이메일로 전송했습니다.",
125+
null
126+
));
127+
}
114128
}

src/main/java/com/back/domain/user/service/AuthService.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,24 @@ public void recoverUsername(String email) {
285285
emailService.sendUsernameEmail(user.getEmail(), maskedUsername);
286286
}
287287

288+
/**
289+
* 비밀번호 재설정 요청 서비스
290+
* 1. 이메일로 사용자 조회
291+
* 2. 비밀번호 재설정 토큰 생성
292+
* 3. 이메일 발송
293+
*/
294+
public void recoverPassword(String email) {
295+
// 사용자 조회
296+
User user = userRepository.findByEmail(email)
297+
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
298+
299+
// 비밀번호 재설정 토큰 생성
300+
String resetToken = tokenService.createPasswordResetToken(user.getId());
301+
302+
// 이메일 발송
303+
emailService.sendPasswordResetEmail(user.getEmail(), resetToken);
304+
}
305+
288306
/**
289307
* 회원가입 시 중복 검증
290308
* - username, email, nickname

src/main/java/com/back/domain/user/service/EmailService.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,27 @@ public void sendUsernameEmail(String toEmail, String maskedUsername) {
5757
sendHtmlEmail(toEmail, subject, htmlContent);
5858
}
5959

60+
// 비밀번호 재설정 메일 전송
61+
public void sendPasswordResetEmail(String toEmail, String token) {
62+
String subject = "[Catfe] 비밀번호 재설정 안내";
63+
String resetUrl = FRONTEND_BASE_URL + "/reset-password?token=" + token;
64+
65+
String htmlContent = """
66+
<p>안녕하세요, Catfe입니다.</p>
67+
<p>아래 버튼을 클릭하여 비밀번호를 재설정해 주세요.</p>
68+
<br>
69+
<p>
70+
<a href="%s" style="display:inline-block;padding:10px 20px;
71+
background-color:#4CAF50;color:#fff;text-decoration:none;
72+
border-radius:5px;">비밀번호 재설정하기</a>
73+
</p>
74+
<br>
75+
<p>이 링크는 1시간 동안만 유효합니다.</p>
76+
""".formatted(resetUrl);
77+
78+
sendHtmlEmail(toEmail, subject, htmlContent);
79+
}
80+
6081
// HTML 이메일 전송 공통 메서드
6182
private void sendHtmlEmail(String toEmail, String subject, String htmlContent) {
6283
try {

src/main/java/com/back/domain/user/service/TokenService.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ public void deleteEmailVerificationToken(String token) {
2929
deleteToken(EMAIL_VERIFICATION_PREFIX, token);
3030
}
3131

32+
// -------------------- 비밀번호 재설정 토큰 --------------------
33+
private static final String PASSWORD_RESET_PREFIX = "password:reset:";
34+
private static final long PASSWORD_RESET_EXPIRATION_MINUTES = 60; // 1시간
35+
36+
public String createPasswordResetToken(Long userId) {
37+
return createToken(PASSWORD_RESET_PREFIX, userId, PASSWORD_RESET_EXPIRATION_MINUTES);
38+
}
39+
40+
public Long getUserIdByPasswordResetToken(String token) {
41+
return getUserIdByToken(PASSWORD_RESET_PREFIX, token);
42+
}
43+
44+
public void deletePasswordResetToken(String token) {
45+
deleteToken(PASSWORD_RESET_PREFIX, token);
46+
}
47+
3248
// -------------------- 내부 공통 로직 --------------------
3349
private String createToken(String prefix, Long userId, long ttlMinutes) {
3450
String token = UUID.randomUUID().toString();

0 commit comments

Comments
 (0)