Skip to content

Commit 4a332e4

Browse files
committed
Feat: 비밀번호 변경 API 구현
1 parent b431567 commit 4a332e4

File tree

5 files changed

+88
-15
lines changed

5 files changed

+88
-15
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.back.domain.user.controller;
22

3+
import com.back.domain.user.dto.ChangePasswordRequest;
34
import com.back.domain.user.dto.UpdateUserProfileRequest;
45
import com.back.domain.user.dto.UserDetailResponse;
56
import com.back.domain.user.service.UserService;
@@ -41,8 +42,20 @@ public ResponseEntity<RsData<UserDetailResponse>> updateMyProfile(
4142
.ok(RsData.success(
4243
"회원 정보를 수정했습니다.",
4344
updated
44-
)
45-
);
45+
));
46+
}
47+
48+
// 내 비밀번호 변경
49+
@PatchMapping("/me/password")
50+
public ResponseEntity<RsData<Void>> changeMyPassword(
51+
@AuthenticationPrincipal CustomUserDetails user,
52+
@Valid @RequestBody ChangePasswordRequest request
53+
) {
54+
userService.changePassword(user.getUserId(), request);
55+
return ResponseEntity
56+
.ok(RsData.success(
57+
"비밀번호가 변경되었습니다."
58+
));
4659
}
4760

4861
// 내 계정 삭제
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.back.domain.user.dto;
2+
3+
import jakarta.validation.constraints.NotBlank;
4+
5+
/**
6+
* 비밀번호 변경 요청을 나타내는 DTO
7+
*
8+
* @param currentPassword 현재 비밀번호
9+
* @param newPassword 새로운 비밀번호
10+
*/
11+
public record ChangePasswordRequest(
12+
@NotBlank String currentPassword,
13+
@NotBlank String newPassword
14+
) {
15+
}

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.back.global.exception.ErrorCode;
1616
import com.back.global.security.jwt.JwtTokenProvider;
1717
import com.back.global.util.CookieUtil;
18+
import com.back.global.util.PasswordValidator;
1819
import jakarta.servlet.http.Cookie;
1920
import jakarta.servlet.http.HttpServletRequest;
2021
import jakarta.servlet.http.HttpServletResponse;
@@ -48,7 +49,7 @@ public UserResponse register(UserRegisterRequest request) {
4849
validateDuplicate(request);
4950

5051
// 비밀번호 정책 검증
51-
validatePasswordPolicy(request.password());
52+
PasswordValidator.validate(request.password());
5253

5354
// User 엔티티 생성 (기본 Role.USER, Status.PENDING)
5455
User user = User.createUser(
@@ -216,18 +217,6 @@ private void validateDuplicate(UserRegisterRequest request) {
216217
}
217218
}
218219

219-
/**
220-
* 비밀번호 정책 검증
221-
* - 최소 8자 이상
222-
* - 숫자 및 특수문자 반드시 포함
223-
*/
224-
private void validatePasswordPolicy(String password) {
225-
String regex = "^(?=.*[0-9])(?=.*[!@#$%^&*]).{8,}$";
226-
if (!password.matches(regex)) {
227-
throw new CustomException(ErrorCode.INVALID_PASSWORD);
228-
}
229-
}
230-
231220
/**
232221
* 쿠키에서 Refresh Token 추출
233222
*/

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.back.domain.user.service;
22

3+
import com.back.domain.user.dto.ChangePasswordRequest;
34
import com.back.domain.user.dto.UpdateUserProfileRequest;
45
import com.back.domain.user.dto.UserDetailResponse;
56
import com.back.domain.user.entity.User;
@@ -9,7 +10,9 @@
910
import com.back.domain.user.repository.UserRepository;
1011
import com.back.global.exception.CustomException;
1112
import com.back.global.exception.ErrorCode;
13+
import com.back.global.util.PasswordValidator;
1214
import lombok.RequiredArgsConstructor;
15+
import org.springframework.security.crypto.password.PasswordEncoder;
1316
import org.springframework.stereotype.Service;
1417
import org.springframework.transaction.annotation.Transactional;
1518

@@ -19,6 +22,7 @@
1922
public class UserService {
2023
private final UserRepository userRepository;
2124
private final UserProfileRepository userProfileRepository;
25+
private final PasswordEncoder passwordEncoder;
2226

2327
/**
2428
* 사용자 정보 조회 서비스
@@ -62,6 +66,30 @@ public UserDetailResponse updateUserProfile(Long userId, UpdateUserProfileReques
6266
return UserDetailResponse.from(user);
6367
}
6468

69+
/**
70+
* 비밀번호 변경 서비스
71+
* 1. 사용자 조회 및 상태 검증
72+
* 2. 현재 비밀번호 검증
73+
* 3. 새 비밀번호 정책 검증
74+
* 4. 비밀번호 변경
75+
*/
76+
public void changePassword(Long userId, ChangePasswordRequest request) {
77+
78+
// 사용자 조회 및 상태 검증
79+
User user = getValidUser(userId);
80+
81+
// 현재 비밀번호 검증
82+
if (!passwordEncoder.matches(request.currentPassword(), user.getPassword())) {
83+
throw new CustomException(ErrorCode.INVALID_CREDENTIALS);
84+
}
85+
86+
// 새 비밀번호 정책 검증
87+
PasswordValidator.validate(request.newPassword());
88+
89+
// 비밀번호 변경
90+
user.setPassword(passwordEncoder.encode(request.newPassword()));
91+
}
92+
6593
/**
6694
* 사용자 탈퇴 서비스 (soft delete)
6795
* 1. 사용자 조회 및 상태 검증
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.back.global.util;
2+
3+
import com.back.global.exception.CustomException;
4+
import com.back.global.exception.ErrorCode;
5+
6+
/**
7+
* 비밀번호 유효성 검증 유틸리티 클래스
8+
*
9+
* 비밀번호 정책:
10+
* - 최소 8자 이상
11+
* - 최소 하나의 숫자 포함
12+
* - 최소 하나의 특수문자 포함 (!@#$%^&*)
13+
*/
14+
public class PasswordValidator {
15+
private static final String PASSWORD_REGEX = "^(?=.*[0-9])(?=.*[!@#$%^&*]).{8,}$";
16+
17+
/**
18+
* 비밀번호 유효성 검증 메서드
19+
*
20+
* @param password 검증할 비밀번호
21+
* @throws CustomException 비밀번호가 정책에 맞지 않을 경우 USER_005 예외 발생
22+
*/
23+
public static void validate(String password) {
24+
if (!password.matches(PASSWORD_REGEX)) {
25+
throw new CustomException(ErrorCode.INVALID_PASSWORD);
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)