Skip to content

Commit a407101

Browse files
jbh010204jbh010204
andauthored
RINGUS-67: 비밀번호 재설정 기능 구현 (#74)
* RINGUS-67 refactor: 예외 처리 code도 반환하게 변경 * RINGUS-67 refactor: password 검증 패턴 유틸로 변경 * RINGUS-67 feat: 비밀번호 재설성 기능 구현 --------- Co-authored-by: jbh010204 <j@2180130>
1 parent 10ee9ce commit a407101

File tree

13 files changed

+106
-17
lines changed

13 files changed

+106
-17
lines changed

src/main/java/es/princip/ringus/application/auth/service/AuthService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public SignUpResponse signUp(SignUpRequest request, HttpSession session){
3737

3838
emailSessionRepository.deleteById(sessionId);
3939

40+
verificationService.deleteSession(sessionId);
4041
return new SignUpResponse(member.getId());
4142
}
4243

src/main/java/es/princip/ringus/application/auth/service/EmailVerificationService.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import es.princip.ringus.domain.exception.SignUpErrorCode;
99
import es.princip.ringus.domain.member.MemberRepository;
1010
import es.princip.ringus.global.exception.CustomRuntimeException;
11+
import es.princip.ringus.presentation.auth.dto.request.GenerateCodeRequest;
1112
import jakarta.annotation.PostConstruct;
1213
import jakarta.servlet.http.HttpSession;
1314
import jakarta.transaction.Transactional;
@@ -35,14 +36,21 @@ public void init(){
3536
}
3637

3738
@Transactional
38-
public void generateVerificationCode(String email) {
39-
if(memberRepository.existsByEmail(email)){
40-
throw new CustomRuntimeException(SignUpErrorCode.DUPLICATE_EMAIL);
39+
public void generateVerificationCode(GenerateCodeRequest request) {
40+
if(request.isPasswordReset()) {
41+
if (!memberRepository.existsByEmail(request.email())) {
42+
throw new CustomRuntimeException(SignUpErrorCode.NOT_FOUND_MEMBER);
43+
}
44+
}
45+
else {
46+
if(memberRepository.existsByEmail(request.email())) {
47+
throw new CustomRuntimeException(SignUpErrorCode.DUPLICATE_EMAIL);
48+
}
4149
}
4250

43-
EmailVerification verification = EmailVerification.of(email);
51+
EmailVerification verification = EmailVerification.of(request.email());
4452

45-
emailSendService.sendMimeMessage(email, verification.getVerificationCode());
53+
emailSendService.sendMimeMessage(request.email(), verification.getVerificationCode());
4654

4755
verificationRepository.save(verification);
4856
}
@@ -91,6 +99,13 @@ public void verifySession(String email, HttpSession session){
9199
throw new CustomRuntimeException(EmailErrorCode.SESSION_EMAIL_MISMATCH);
92100
}
93101

94-
sessionRepository.delete(emailSession);
102+
}
103+
104+
@Transactional
105+
public void deleteSession(String email) {
106+
if(!sessionRepository.existsById(email)) {
107+
throw new CustomRuntimeException(EmailErrorCode.SESSION_NOT_FOUND);
108+
}
109+
sessionRepository.deleteById(email);
95110
}
96111
}

src/main/java/es/princip/ringus/application/member/service/MemberService.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package es.princip.ringus.application.member.service;
22

3+
import es.princip.ringus.application.auth.service.EmailVerificationService;
34
import es.princip.ringus.domain.exception.MemberErrorCode;
45
import es.princip.ringus.domain.exception.SignUpErrorCode;
56
import es.princip.ringus.domain.member.Member;
@@ -16,6 +17,8 @@
1617
import es.princip.ringus.presentation.member.dto.MemberResponse;
1718
import es.princip.ringus.presentation.member.dto.MenteeProfileResponse;
1819
import es.princip.ringus.presentation.member.dto.MentorProfileResponse;
20+
import es.princip.ringus.presentation.member.dto.PasswordUpdateRequest;
21+
import jakarta.servlet.http.HttpSession;
1922
import lombok.RequiredArgsConstructor;
2023
import lombok.extern.slf4j.Slf4j;
2124
import org.springframework.security.crypto.password.PasswordEncoder;
@@ -31,9 +34,10 @@
3134
public class MemberService {
3235
private final MemberRepository memberRepository;
3336
private final MentorRepository mentorRepository;
34-
private final MenteeRepository menteeRepository;
37+
private final MenteeRepository menteeRepository;
3538
private final PasswordEncoder passwordEncoder;
3639
private final MentoringRepository mentoringRepository;
40+
private final EmailVerificationService emailVerificationService;
3741

3842
/**
3943
* 회원 저장 (이메일 인증 후 회원가입 진행)
@@ -77,6 +81,23 @@ public MemberResponse getMember(Long memberId) {
7781
return MemberResponse.of(member);
7882
}
7983

84+
@Transactional
85+
public void updatePassword(PasswordUpdateRequest request, HttpSession session) {
86+
emailVerificationService.verifySession(request.email(), session);
87+
88+
Member member = memberRepository.findByEmail(request.email())
89+
.orElseThrow(() -> new CustomRuntimeException(SignUpErrorCode.NOT_FOUND_MEMBER));
90+
91+
if (passwordEncoder.matches(request.newPassword(), member.getPassword())) {
92+
throw new CustomRuntimeException(MemberErrorCode.DUPLICATE_EXISTING_PASSWORD);
93+
}
94+
95+
member.updatePassword(request.newPassword(), passwordEncoder);
96+
97+
emailVerificationService.deleteSession(request.email());
98+
99+
}
100+
80101
public boolean isUniqueNickname(String nickname) {
81102
return !mentorRepository.existsByNickname(nickname) && !menteeRepository.existsByNickname(nickname);
82103
}

src/main/java/es/princip/ringus/domain/exception/EmailErrorCode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
public enum EmailErrorCode implements ErrorCode {
77

8-
SUCESSS_VALILDATION(HttpStatus.OK, "성공적으로 인증되었습니다"),
8+
SUCESSS_VAILDATION(HttpStatus.OK, "성공적으로 인증되었습니다"),
99
TTL_EXPIRED(HttpStatus.FORBIDDEN, "TTL 만료"),
1010
ERROR_EXCEEDED_ATTEMPTS(HttpStatus.FORBIDDEN, "인증번호 틀림 횟수 5회 이상, 새로운 인증번호를 발급 받아주세요"),
1111
ERROR_INVALID_CODE(HttpStatus.BAD_REQUEST, "인증번호가 틀립니다"),

src/main/java/es/princip/ringus/domain/exception/MemberErrorCode.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ public enum MemberErrorCode implements ErrorCode {
77

88
SESSION_EXPIRED(HttpStatus.UNAUTHORIZED, "세션이 거부됨"),
99
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "멤버를 찾을 수 없음"),
10-
MEMBER_TYPE_DIFFERENT(HttpStatus.BAD_REQUEST, "다른 멤버 타입");
10+
MEMBER_TYPE_DIFFERENT(HttpStatus.BAD_REQUEST, "다른 멤버 타입"),
11+
INVAILD_PASSWORD(HttpStatus.BAD_REQUEST, "비밀번호가 유효하지 않음"),
12+
DUPLICATE_EXISTING_PASSWORD(HttpStatus.BAD_REQUEST, "이미 사용 중인 비밀번호입니다.");
1113

1214
MemberErrorCode(HttpStatus status, String message) {
1315
this.status = status;

src/main/java/es/princip/ringus/domain/member/Member.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,8 @@ public boolean isMentor() {
101101
public boolean isMentee() {
102102
return this.memberType == MemberType.ROLE_MENTEE;
103103
}
104+
105+
public void updatePassword(String newPassword, PasswordEncoder passwordEncoder) {
106+
this.password = passwordEncoder.encode(newPassword);
107+
}
104108
}

src/main/java/es/princip/ringus/global/exception/GlobalExceptionHandler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public ResponseEntity<Map<String, Object>> handleCustomRuntimeException(CustomRu
9595
Map<String, Object> response = new LinkedHashMap<>();
9696
response.put("status", ex.getStatus().value());
9797
response.put("message", ex.getMessage());
98+
response.put("code", ex.getCode());
9899

99100
return ResponseEntity.status(ex.getStatus()).body(response);
100101
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package es.princip.ringus.global.util;
2+
3+
import es.princip.ringus.domain.exception.MemberErrorCode;
4+
import es.princip.ringus.global.exception.CustomRuntimeException;
5+
import java.util.regex.Pattern;
6+
7+
public class PasswordVaildator {
8+
private static final String PASSWORD_PATTERN = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*_+=/])[A-Za-z\\d!@#$%^&*_+=/]{8,20}$";
9+
10+
public static void validate(String password) {
11+
if (!Pattern.matches(PASSWORD_PATTERN, password)) {
12+
throw new CustomRuntimeException(MemberErrorCode.INVAILD_PASSWORD);
13+
}
14+
}
15+
}

src/main/java/es/princip/ringus/presentation/auth/AuthController.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import es.princip.ringus.application.auth.service.EmailVerificationService;
55
import es.princip.ringus.global.util.ApiResponseWrapper;
66
import es.princip.ringus.global.util.CookieUtil;
7+
import es.princip.ringus.global.util.PasswordVaildator;
78
import es.princip.ringus.presentation.auth.dto.request.EmailVerifyRequest;
89
import es.princip.ringus.presentation.auth.dto.request.GenerateCodeRequest;
910
import es.princip.ringus.presentation.auth.dto.request.LoginRequest;
@@ -14,6 +15,7 @@
1415
import jakarta.servlet.http.HttpServletResponse;
1516
import jakarta.servlet.http.HttpSession;
1617
import jakarta.validation.Valid;
18+
import java.net.URI;
1719
import lombok.RequiredArgsConstructor;
1820
import lombok.extern.slf4j.Slf4j;
1921
import org.springframework.http.HttpStatus;
@@ -23,8 +25,6 @@
2325
import org.springframework.web.bind.annotation.RequestMapping;
2426
import org.springframework.web.bind.annotation.RestController;
2527

26-
import java.net.URI;
27-
2828
@Slf4j
2929
@RestController
3030
@RequiredArgsConstructor
@@ -38,6 +38,8 @@ public class AuthController implements AuthControllerDocs{
3838
@PostMapping("/signup")
3939
public ResponseEntity<?> signUp(@Valid @RequestBody SignUpRequest request, HttpSession session, HttpServletResponse httpResponse) {
4040

41+
PasswordVaildator.validate(request.password());
42+
4143
SignUpResponse response = authService.signUp(request, session);
4244

4345
CookieUtil.deleteCookie(httpResponse, "JSESSIONID");
@@ -76,7 +78,7 @@ public ResponseEntity<ApiResponseWrapper<Void>> logout(HttpSession session, Http
7678

7779
@PostMapping("/email/code")
7880
public ResponseEntity<ApiResponseWrapper<Void>> requestCode(@Valid @RequestBody GenerateCodeRequest request) {
79-
emailVerificationService.generateVerificationCode(request.email());
81+
emailVerificationService.generateVerificationCode(request);
8082

8183
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "인증번호가 발급되었습니다"));
8284
}

src/main/java/es/princip/ringus/presentation/auth/dto/request/GenerateCodeRequest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55

66
public record GenerateCodeRequest(
77
@Email @NotBlank
8-
String email
8+
String email,
9+
10+
@NotBlank
11+
Boolean isPasswordReset
912
) { }

0 commit comments

Comments
 (0)