Skip to content

Commit 735bf5d

Browse files
authored
Refactor : 이메일 인증 및 비밀번호 재설정 링크 구조 개선 및 redirectUrl 적용 (#96)
* refactor : 이메일 인즈에 redirectUrl 추가 * text : 주석 추가 * refactor : 이메일 인즈에 redirectUrl 추가 * text : 주석 추가 * Swagger 추가
1 parent f3db1e5 commit 735bf5d

File tree

10 files changed

+84
-44
lines changed

10 files changed

+84
-44
lines changed

src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/request/FindPasswordRequest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@
99
@Schema(description = "비밀번호 찾기 요청")
1010
public class FindPasswordRequest {
1111
private String email;
12+
private String redirectUrl;
1213
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.ezcode.codetest.application.usermanagement.auth.dto.request;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
@Getter
7+
@AllArgsConstructor
8+
public class ResetPasswordRequest {
9+
private String email;
10+
private String newPassword;
11+
private String token;
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.ezcode.codetest.application.usermanagement.auth.dto.request;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
7+
@Getter
8+
@AllArgsConstructor
9+
@Schema(description = "이메일 전송 요청")
10+
public class SendEmailRequest {
11+
@Schema(description = "인증 완료 후 리다이렉트할 URL")
12+
private String redirectUrl;
13+
}

src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/response/SendEmailCodeResponse.java renamed to src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/response/SendEmailResponse.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
import io.swagger.v3.oas.annotations.media.Schema;
44

55
@Schema(description = "인증코드 전송 성공")
6-
public record SendEmailCodeResponse(
6+
public record SendEmailResponse(
77
@Schema(description = "인증코드 전송 성공 메세지")
88
String message
99
) {
10-
public static SendEmailCodeResponse from(String message) {
11-
return new SendEmailCodeResponse(message);
10+
public static SendEmailResponse from(String message) {
11+
return new SendEmailResponse(message);
1212
}
1313
}

src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
import java.util.concurrent.TimeUnit;
55

66
import org.ezcode.codetest.application.usermanagement.auth.dto.request.FindPasswordRequest;
7-
import org.ezcode.codetest.application.usermanagement.auth.dto.request.VerifyEmailCodeRequest;
7+
import org.ezcode.codetest.application.usermanagement.auth.dto.request.ResetPasswordRequest;
88
import org.ezcode.codetest.application.usermanagement.auth.dto.response.FindPasswordResponse;
99
import org.ezcode.codetest.application.usermanagement.auth.dto.response.RefreshTokenResponse;
1010
import org.ezcode.codetest.application.usermanagement.auth.dto.request.SigninRequest;
11-
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SendEmailCodeResponse;
11+
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SendEmailResponse;
1212
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SigninResponse;
1313
import org.ezcode.codetest.application.usermanagement.auth.dto.request.SignupRequest;
1414
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SignupResponse;
@@ -100,9 +100,9 @@ private void updateExistingUser(User existUser, String encodedPassword) {
100100
}
101101

102102
@Transactional
103-
public SendEmailCodeResponse sendEmailCode(Long userId, String email) {
104-
mailService.sendButtonMail(userId, email);
105-
return SendEmailCodeResponse.from("인증 코드를 전송했습니다.");
103+
public SendEmailResponse sendEmailCode(Long userId, String email, String redirectUrl) {
104+
mailService.sendButtonMail(userId, email, redirectUrl);
105+
return SendEmailResponse.from("인증 코드를 전송했습니다.");
106106
}
107107

108108
@Transactional
@@ -226,20 +226,22 @@ public FindPasswordResponse findPassword(FindPasswordRequest request) {
226226
throw new AuthException(AuthExceptionCode.USER_NOT_FOUND);
227227
}
228228

229-
mailService.sendPasswordMail(user.getId(), request.getEmail());
229+
mailService.sendPasswordMail(user.getId(), request.getEmail(), request.getRedirectUrl());
230230

231231
return FindPasswordResponse.from("이메일로 전송되었습니다.");
232232
}
233233

234234
//메일로 받은 링크를 통해 비번 변경
235-
public FindPasswordResponse changePasswordByEmail(String email, String key) {
235+
public FindPasswordResponse resetPassword(ResetPasswordRequest request) {
236236

237-
User user = userDomainService.getUserByEmail(email);
237+
User user = userDomainService.getUserByEmail(request.getEmail());
238238

239-
boolean isMatch = mailService.verifyCode(user.getId(), key);
239+
boolean isMatch = mailService.verifyPasswordCode(user.getId(), request.getToken());
240240

241241
if (isMatch){
242-
return FindPasswordResponse.from("인증되었습니다");
242+
String encodedPassword = userDomainService.encodePassword(request.getNewPassword());
243+
user.modifyPassword(encodedPassword);
244+
return FindPasswordResponse.from("비밀번호가 변경되었습니다.");
243245
} else {
244246
throw new UserException(UserExceptionCode.NOT_MATCH_CODE);
245247
}

src/main/java/org/ezcode/codetest/application/usermanagement/user/service/UserService.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
import java.time.temporal.ChronoUnit;
55
import java.util.List;
66

7-
import org.ezcode.codetest.application.usermanagement.auth.dto.request.VerifyEmailCodeRequest;
8-
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SendEmailCodeResponse;
9-
import org.ezcode.codetest.application.usermanagement.auth.dto.response.VerifyEmailCodeResponse;
107
import org.ezcode.codetest.application.usermanagement.user.model.UsersByWeek;
118
import org.ezcode.codetest.domain.submission.dto.WeeklySolveCount;
129
import org.ezcode.codetest.application.usermanagement.user.dto.request.ChangeUserPasswordRequest;
@@ -16,9 +13,7 @@
1613
import org.ezcode.codetest.application.usermanagement.user.dto.response.WithdrawUserResponse;
1714
import org.ezcode.codetest.domain.submission.service.SubmissionDomainService;
1815
import org.ezcode.codetest.domain.user.exception.AuthException;
19-
import org.ezcode.codetest.domain.user.exception.UserException;
2016
import org.ezcode.codetest.domain.user.exception.code.AuthExceptionCode;
21-
import org.ezcode.codetest.domain.user.exception.code.UserExceptionCode;
2217
import org.ezcode.codetest.domain.user.model.entity.AuthUser;
2318
import org.ezcode.codetest.domain.user.model.entity.User;
2419
import org.ezcode.codetest.domain.user.model.enums.AuthType;
@@ -29,7 +24,6 @@
2924

3025
import org.springframework.transaction.annotation.Transactional;
3126

32-
import jakarta.validation.Valid;
3327
import lombok.RequiredArgsConstructor;
3428
import lombok.extern.slf4j.Slf4j;
3529

src/main/java/org/ezcode/codetest/common/security/config/SecurityConfig.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.springframework.context.annotation.Bean;
1313
import org.springframework.context.annotation.Configuration;
1414
import org.springframework.data.redis.core.RedisTemplate;
15+
import org.springframework.http.HttpMethod;
1516
import org.springframework.security.config.Customizer;
1617
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
1718
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -71,6 +72,10 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
7172
.requestMatchers(new DispatcherTypeRequestMatcher(DispatcherType.ASYNC)).permitAll()
7273
.requestMatchers(
7374
SecurityPath.PUBLIC_PATH).permitAll()
75+
.requestMatchers(HttpMethod.GET,
76+
"/api/problems/*/discussions",
77+
"/api/problems/{problemId}/discussions/{discussionId}/replies",
78+
"/api/problems/{problemId}/discussions/{discussionId}/replies/**").permitAll()
7479
.requestMatchers("/admin/**").hasRole("ADMIN") //어드민 권한 필요 (문제 생성, 관리 등)
7580
.anyRequest().authenticated() //나머지는 일반 인증
7681
)

src/main/java/org/ezcode/codetest/domain/user/service/MailService.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ public void sendCodeMail(Long userId, String email) {
3030
javaMailSender.send(message);
3131
}
3232

33-
public void sendButtonMail(Long userId, String email) {
34-
MimeMessage message = CreateButtonMail(userId, email);
33+
public void sendButtonMail(Long userId, String email, String redirectUrl) {
34+
MimeMessage message = CreateButtonMail(userId, email, redirectUrl);
3535
javaMailSender.send(message);
3636
}
3737

38-
public void sendPasswordMail(Long userId, String email) {
39-
MimeMessage message = CreatePasswordMail(userId, email);
38+
public void sendPasswordMail(Long userId, String email, String redirectUrl) {
39+
MimeMessage message = CreatePasswordMail(userId, email, redirectUrl);
4040
javaMailSender.send(message);
4141
}
4242

43-
public MimeMessage CreateButtonMail(Long userId, String email) {
43+
public MimeMessage CreateButtonMail(Long userId, String email, String redirectUrl) {
4444
MimeMessage message = javaMailSender.createMimeMessage();
4545
String key = createNumber(userId); //radis에 유저id&코드로 저장 (10분)
4646

@@ -51,7 +51,7 @@ public MimeMessage CreateButtonMail(Long userId, String email) {
5151
String body = "";
5252
body += "<h3>" + "아래 버튼을 클릭하여 이메일 인증을 완료해 주세요" + "</h3>";
5353
// 이메일 버튼
54-
body += "<a href='http://localhost:8080/api/auth/verify?email="+ email + "&key=" + key + "' target='_blenk'>이메일 인증 확인</a>";
54+
body += "<a href='" + redirectUrl + "/api/auth/verify?email="+ email + "&key=" + key + "' target='_blenk'>이메일 인증 확인</a>";
5555
body += "<h3>" + "감사합니다." + "</h3>";
5656
message.setText(body,"UTF-8", "html");
5757
} catch (MessagingException e) {
@@ -61,7 +61,7 @@ public MimeMessage CreateButtonMail(Long userId, String email) {
6161
return message;
6262
}
6363

64-
public MimeMessage CreatePasswordMail(Long userId, String email){
64+
public MimeMessage CreatePasswordMail(Long userId, String email, String redirectUrl){
6565
MimeMessage message = javaMailSender.createMimeMessage();
6666

6767
String redisKey = "PASSWORD_KEY:" + userId;
@@ -81,7 +81,7 @@ public MimeMessage CreatePasswordMail(Long userId, String email){
8181
String body = "";
8282
body += "<h3>" + "아래 버튼을 클릭하여 비밀번호 변경을 완료해 주세요" + "</h3>";
8383
// 이메일 버튼
84-
body += "<a href='http://localhost:8080/api/auth/password?email="+ email + "&key=" + verificationCode + "' target='_blenk'>비밀번호 변경하기</a>";
84+
body += "<a href='"+redirectUrl+"/api/auth/reset-password?email="+ email + "&key=" + verificationCode + "' target='_blenk'>비밀번호 변경하기</a>";
8585
body += "<h3>" + "감사합니다." + "</h3>";
8686
message.setText(body,"UTF-8", "html");
8787
} catch (MessagingException e) {
@@ -155,4 +155,22 @@ public boolean verifyCode(Long userId, String inputCode) {
155155
return isMatch;
156156
}
157157

158+
// 비밀번호 검증
159+
public boolean verifyPasswordCode(Long userId, String inputCode) {
160+
String key = "PASSWORD_KEY:" + userId;
161+
String storedCode = redisTemplate.opsForValue().get(key);
162+
163+
if (storedCode == null) {
164+
log.warn("비밀번호 재설정 코드가 없음 : {}", userId);
165+
return false;
166+
}
167+
168+
boolean isMatch = inputCode != null && inputCode.trim().equals(storedCode);
169+
170+
if (isMatch) {
171+
redisTemplate.delete(key);
172+
}
173+
return isMatch;
174+
}
175+
158176
}

src/main/java/org/ezcode/codetest/presentation/usermanagement/AuthController.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
import java.util.Optional;
44

55
import org.ezcode.codetest.application.usermanagement.auth.dto.request.FindPasswordRequest;
6-
import org.ezcode.codetest.application.usermanagement.auth.dto.request.VerifyEmailCodeRequest;
6+
import org.ezcode.codetest.application.usermanagement.auth.dto.request.ResetPasswordRequest;
7+
import org.ezcode.codetest.application.usermanagement.auth.dto.request.SendEmailRequest;
78
import org.ezcode.codetest.application.usermanagement.auth.dto.response.FindPasswordResponse;
89
import org.ezcode.codetest.application.usermanagement.auth.dto.response.RefreshTokenResponse;
910
import org.ezcode.codetest.application.usermanagement.auth.dto.request.SigninRequest;
10-
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SendEmailCodeResponse;
11+
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SendEmailResponse;
1112
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SigninResponse;
1213
import org.ezcode.codetest.application.usermanagement.auth.dto.request.SignupRequest;
1314
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SignupResponse;
@@ -22,11 +23,9 @@
2223
import org.springframework.security.core.annotation.AuthenticationPrincipal;
2324
import org.springframework.web.bind.annotation.GetMapping;
2425
import org.springframework.web.bind.annotation.PostMapping;
25-
import org.springframework.web.bind.annotation.PutMapping;
2626
import org.springframework.web.bind.annotation.RequestBody;
2727
import org.springframework.web.bind.annotation.RequestMapping;
2828
import org.springframework.web.bind.annotation.RequestParam;
29-
import org.springframework.web.bind.annotation.ResponseBody;
3029
import org.springframework.web.bind.annotation.RestController;
3130

3231
import io.swagger.v3.oas.annotations.Operation;
@@ -86,10 +85,11 @@ public ResponseEntity<RefreshTokenResponse> refresh(HttpServletRequest request)
8685

8786
@Operation(summary = "이메일 인증 코드 전송", description = "현재 로그인된 회원의 이메일로 인증 코드를 전송합니다.")
8887
@PostMapping("/email/send")
89-
public ResponseEntity<SendEmailCodeResponse> sendMailCode(
90-
@AuthenticationPrincipal AuthUser authUser
88+
public ResponseEntity<SendEmailResponse> sendMailCode(
89+
@AuthenticationPrincipal AuthUser authUser,
90+
@RequestBody SendEmailRequest request
9191
){
92-
return ResponseEntity.status(HttpStatus.CREATED).body(authService.sendEmailCode(authUser.getId(), authUser.getEmail()));
92+
return ResponseEntity.status(HttpStatus.CREATED).body(authService.sendEmailCode(authUser.getId(), authUser.getEmail(), request.getRedirectUrl()));
9393
}
9494

9595
//이메일에서 버튼 클릭하면 자동으로 연결
@@ -102,19 +102,18 @@ public ResponseEntity<VerifyEmailCodeResponse> verifyEmailCode(
102102
return ResponseEntity.status(HttpStatus.OK).body(authService.verifyEmailCode(email, key));
103103
}
104104

105-
105+
//미완성 -> 메일 전송까지는 성공
106106
@PostMapping("/auth/find-password")
107107
public ResponseEntity<FindPasswordResponse> findPassword(
108108
@RequestBody FindPasswordRequest request
109109
){
110110
return ResponseEntity.status(HttpStatus.OK).body(authService.findPassword(request));
111111
}
112112

113-
@GetMapping("/auth/verify-password-code")
114-
public ResponseEntity<FindPasswordResponse> changePasswordByEmail(
115-
@RequestParam String email,
116-
@RequestParam String key
113+
@PostMapping("/auth/reset-password")
114+
public ResponseEntity<FindPasswordResponse> resetPassword(
115+
@RequestBody ResetPasswordRequest request
117116
){
118-
return ResponseEntity.status(HttpStatus.OK).body(authService.changePasswordByEmail(email, key));
117+
return ResponseEntity.status(HttpStatus.OK).body(authService.resetPassword(request));
119118
}
120119
}

src/main/java/org/ezcode/codetest/presentation/usermanagement/UserController.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package org.ezcode.codetest.presentation.usermanagement;
22

3-
import org.ezcode.codetest.application.usermanagement.auth.dto.request.VerifyEmailCodeRequest;
4-
import org.ezcode.codetest.application.usermanagement.auth.dto.response.SendEmailCodeResponse;
5-
import org.ezcode.codetest.application.usermanagement.auth.dto.response.VerifyEmailCodeResponse;
63
import org.ezcode.codetest.application.usermanagement.user.dto.request.ModifyUserInfoRequest;
74
import org.ezcode.codetest.application.usermanagement.user.dto.request.ChangeUserPasswordRequest;
85
import org.ezcode.codetest.application.usermanagement.user.dto.response.ChangeUserPasswordResponse;
@@ -15,7 +12,6 @@
1512
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1613
import org.springframework.web.bind.annotation.DeleteMapping;
1714
import org.springframework.web.bind.annotation.GetMapping;
18-
import org.springframework.web.bind.annotation.PostMapping;
1915
import org.springframework.web.bind.annotation.PutMapping;
2016
import org.springframework.web.bind.annotation.RequestBody;
2117
import org.springframework.web.bind.annotation.RequestMapping;

0 commit comments

Comments
 (0)