Skip to content

Commit 97f27ac

Browse files
author
jbh010204
committed
RINGUS-67 feat: 비밀번호 재설성 기능 구현
1 parent a335d09 commit 97f27ac

File tree

10 files changed

+89
-16
lines changed

10 files changed

+89
-16
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/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/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
) { }

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ public record SignUpRequest(
1717

1818
@NotBlank(message = "비밀번호를 입력해주세욘.")
1919
@Size(min = 8, max = 20, message = "비밀번호는 8~20자여야 합니다.")
20-
@Pattern(
21-
regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*_+=/])[A-Za-z\\d!@#$%^&*_+=/]{8,20}$",
22-
message = "비밀번호는 8~20자의 대소문자, 숫자, 특수문자로 구성해야 합니다."
23-
)
2420
String password,
2521

2622
@NotNull Set<ServiceTermAgreementRequest> serviceTerms

src/main/java/es/princip/ringus/presentation/member/MemberController.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
import es.princip.ringus.global.annotation.SessionCheck;
55
import es.princip.ringus.global.annotation.SessionMemberId;
66
import es.princip.ringus.global.util.ApiResponseWrapper;
7+
import es.princip.ringus.global.util.CookieUtil;
8+
import es.princip.ringus.global.util.PasswordVaildator;
79
import es.princip.ringus.presentation.member.dto.MemberResponse;
10+
import es.princip.ringus.presentation.member.dto.PasswordUpdateRequest;
11+
import jakarta.servlet.http.HttpServletResponse;
12+
import jakarta.servlet.http.HttpSession;
813
import lombok.RequiredArgsConstructor;
914
import org.springframework.http.HttpStatus;
1015
import org.springframework.http.ResponseEntity;
@@ -39,4 +44,22 @@ public ResponseEntity<ApiResponseWrapper<Boolean>> isUniqueNickname(@RequestPara
3944
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, response));
4045
}
4146

47+
@SessionCheck
48+
@PatchMapping("/password")
49+
public ResponseEntity<ApiResponseWrapper<Void>> updatePassword(
50+
@RequestBody PasswordUpdateRequest request,
51+
HttpSession session,
52+
HttpServletResponse httpResponse
53+
){
54+
PasswordVaildator.validate(request.newPassword());
55+
56+
memberService.updatePassword(request, session);
57+
58+
CookieUtil.deleteCookie(httpResponse, "JSESSIONID");
59+
60+
session.invalidate();
61+
62+
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "비밀번호가 변경되었습니다."));
63+
}
64+
4265
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package es.princip.ringus.presentation.member.dto;
2+
3+
public record PasswordUpdateRequest(
4+
String email,
5+
String newPassword
6+
) { }

0 commit comments

Comments
 (0)