@@ -55,7 +55,7 @@ public ResponseEntity<MemberResponse> login(@Valid @RequestBody MemberLoginReque
5555 }
5656
5757 @ PostMapping ("/logout" )
58- @ Operation (summary = "08 . 로그아웃" , description = "현재 로그인된 사용자를 로그아웃합니다." )
58+ @ Operation (summary = "09 . 로그아웃" , description = "현재 로그인된 사용자를 로그아웃합니다." )
5959 @ ApiResponses ({
6060 @ ApiResponse (responseCode = "200" , description = "로그아웃 성공" )
6161 })
@@ -98,7 +98,7 @@ public ResponseEntity<MemberResponse> refreshToken(HttpServletRequest request,
9898 }
9999
100100 @ DeleteMapping ("/withdraw" )
101- @ Operation (summary = "09 . 회원탈퇴" , description = "현재 로그인된 사용자의 계정을 삭제합니다." )
101+ @ Operation (summary = "10 . 회원탈퇴" , description = "현재 로그인된 사용자의 계정을 삭제합니다." )
102102 @ ApiResponses ({
103103 @ ApiResponse (responseCode = "200" , description = "회원탈퇴 성공" ),
104104 @ ApiResponse (responseCode = "401" , description = "인증되지 않은 사용자" ),
@@ -198,56 +198,37 @@ public ResponseEntity<EmailResponse> sendEmail(
198198 }
199199
200200 @ PostMapping ("/verifyEmail" )
201- @ Operation (summary = "06. 인증번호 검증" , description = "로그인된 사용자는 자동으로 인증번호를 검증하고, 비로그인 사용자는 요청 바디의 loginId(이메일)와 함께 인증번호를 검증합니다." )
201+ @ Operation (summary = "06. 인증번호 검증" , description = "비로그인 사용자가 이메일로 받은 인증번호를 검증합니다. (비밀번호 재설정용) " )
202202 @ ApiResponses ({
203203 @ ApiResponse (responseCode = "200" , description = "인증번호 검증 성공" ),
204204 @ ApiResponse (responseCode = "400" , description = "잘못된 요청 (인증번호 불일치, loginId 없음)" )
205205 })
206- public ResponseEntity <EmailResponse > verifyEmail (
206+ public ResponseEntity <VerificationResponse > verifyEmail (
207207 @ RequestBody @ Valid EmailVerifyCodeRequestDto requestDto ,
208- Authentication authentication ,
209- HttpServletRequest request ) {
210-
211- String loginId = null ;
208+ Authentication authentication
209+ ) {
212210
213- // 1. 로그인된 사용자인 경우 JWT 토큰에서 loginId 추출 (우선순위 1)
214211 if (authentication != null && authentication .isAuthenticated () &&
215212 !"anonymousUser" .equals (authentication .getPrincipal ())) {
216-
217- // JWT 토큰에서 직접 loginid claim 추출
218- try {
219- String token = extractAccessTokenFromRequest (request );
220- if (token != null ) {
221- loginId = memberService .extractLoginIdFromToken (token );
222- if (loginId != null ) {
223- log .info ("JWT 토큰에서 loginId 추출 성공: {}" , loginId );
224- } else {
225- log .warn ("JWT 토큰에서 loginId 추출 실패" );
226- }
227- }
228- } catch (Exception e ) {
229- log .warn ("JWT 토큰에서 loginId 추출 중 오류: {}" , e .getMessage ());
230- }
213+ log .error ("로그인된 사용자의 이메일 인증 시도" );
214+ throw new IllegalArgumentException ("로그인된 사용자는 비밀번호 검증을 사용해야 합니다." );
231215 }
232216
233- // 2. 비로그인 사용자인 경우 요청 바디에서 loginId 추출 (우선순위 2)
234- if (loginId == null ) {
235- if (requestDto .getLoginId () != null && !requestDto .getLoginId ().isBlank ()) {
236- loginId = requestDto .getLoginId ();
237- log .info ("요청 바디에서 loginId 추출 성공: {}" , loginId );
238- } else {
239- log .error ("로그인하지 않은 상태에서 요청 바디에 loginId가 없음" );
240- throw new IllegalArgumentException ("인증번호를 검증할 이메일 주소가 필요합니다. 로그인하거나 요청 바디에 loginId를 포함해주세요." );
241- }
217+ if (requestDto .getLoginId () == null || requestDto .getLoginId ().isBlank ()) {
218+ log .error ("요청 바디에 loginId가 없음" );
219+ throw new IllegalArgumentException ("인증번호를 검증할 이메일 주소가 필요합니다." );
242220 }
243221
222+ String loginId = requestDto .getLoginId ();
223+ log .info ("이메일 인증번호 검증 요청: {}" , loginId );
224+
244225 try {
245226 // 서비스 호출 - 인증번호 검증
246227 boolean isValid = memberService .verifyAuthCode (loginId , requestDto .getVerificationCode ());
247228
248229 if (isValid ) {
249230 log .info ("이메일 인증번호 검증 성공: {}" , loginId );
250- return ResponseEntity .ok (EmailResponse .success ("인증번호 검증 성공" , loginId ));
231+ return ResponseEntity .ok (VerificationResponse .success ("인증번호 검증 성공" , loginId ));
251232 } else {
252233 log .error ("이메일 인증번호 검증 실패 - 잘못된 인증번호: {}" , loginId );
253234 throw new IllegalArgumentException ("잘못된 인증번호이거나 만료된 인증번호입니다." );
@@ -262,10 +243,63 @@ public ResponseEntity<EmailResponse> verifyEmail(
262243 }
263244 }
264245
265- // ===== 비밀번호 재설정 엔드포인트 =====
246+ @ PostMapping ("/verifyPassword" )
247+ @ Operation (summary = "07. 비밀번호 검증" , description = "로그인된 사용자가 비밀번호를 통해 인증합니다. (비밀번호 재설정용)" )
248+ @ ApiResponses ({
249+ @ ApiResponse (responseCode = "200" , description = "비밀번호 검증 성공" ),
250+ @ ApiResponse (responseCode = "400" , description = "잘못된 요청 (비밀번호 불일치)" ),
251+ @ ApiResponse (responseCode = "401" , description = "인증되지 않은 사용자" )
252+ })
253+ public ResponseEntity <VerificationResponse > verifyPassword (
254+ @ RequestBody @ Valid PasswordVerifyRequestDto requestDto ,
255+ Authentication authentication ,
256+ HttpServletRequest request ){
257+
258+ if (authentication == null || !authentication .isAuthenticated () ||
259+ "anonymousUser" .equals (authentication .getPrincipal ())) {
260+ log .error ("비로그인 사용자의 비밀번호 검증 시도" );
261+ throw new IllegalArgumentException ("비밀번호 검증은 로그인된 사용자만 가능합니다. 비로그인 사용자는 이메일 인증을 사용하세요." );
262+ }
263+
264+ String loginId = null ;
265+ try {
266+ String token = extractAccessTokenFromRequest (request );
267+ if (token != null ) {
268+ loginId = memberService .extractLoginIdFromToken (token );
269+ }
270+ } catch (Exception e ) {
271+ log .warn ("JWT 토큰에서 loginId 추출 중 오류: {}" , e .getMessage ());
272+ }
273+
274+ if (loginId == null ) {
275+ log .error ("JWT 토큰에서 loginId 추출 실패" );
276+ throw new IllegalArgumentException ("유효하지 않은 토큰입니다." );
277+ }
278+
279+ log .info ("비밀번호 검증 요청: {}" , loginId );
280+
281+ try {
282+ boolean isValid = memberService .verifyPassword (loginId , requestDto .getPassword ());
283+
284+ if (isValid ) {
285+ log .info ("비밀번호 검증 성공: {}" , loginId );
286+ return ResponseEntity .ok (VerificationResponse .success ("비밀번호 검증 성공" , loginId ));
287+ } else {
288+ log .error ("비밀번호 검증 실패 - 비밀번호 불일치: {}" , loginId );
289+ throw new IllegalArgumentException ("잘못된 입력입니다." );
290+ }
291+
292+ } catch (IllegalArgumentException e ) {
293+ log .error ("비밀번호 검증 실패: loginId={}, error={}" , loginId , e .getMessage ());
294+ throw e ;
295+ } catch (Exception e ) {
296+ log .error ("비밀번호 검증 중 오류 발생: loginId={}, error={}" , loginId , e .getMessage ());
297+ throw new RuntimeException ("비밀번호 검증 중 오류가 발생했습니다." );
298+ }
299+ }
266300
267301 @ PostMapping ("/password-reset/reset" )
268- @ Operation (summary = "07 . 비밀번호 재설정" , description = "인증 토큰과 함께 새 비밀번호로 재설정합니다." )
302+ @ Operation (summary = "08 . 비밀번호 재설정" , description = "인증 토큰과 함께 새 비밀번호로 재설정합니다." )
269303 @ ApiResponses ({
270304 @ ApiResponse (responseCode = "200" , description = "비밀번호 재설정 성공" ),
271305 @ ApiResponse (responseCode = "400" , description = "인증되지 않았거나 잘못된 요청" )
@@ -285,7 +319,6 @@ public ResponseEntity<PasswordResetResponse> resetPassword(
285319
286320 String loginId = null ;
287321
288- // 1. 로그인된 사용자인 경우 JWT 토큰에서 loginId 추출 (우선순위 1)
289322 if (authentication != null && authentication .isAuthenticated () &&
290323 !"anonymousUser" .equals (authentication .getPrincipal ())) {
291324
@@ -341,7 +374,8 @@ private String extractRefreshTokenFromCookies(HttpServletRequest request) {
341374 }
342375
343376 /**
344- * HTTP 쿠키에서 액세스 토큰을 추출합니다.
377+ * HTTP 요청에서 액세스 토큰을 추출합니다.
378+ * Authorization 헤더 또는 쿠키에서 토큰을 확인합니다.
345379 * @param request HTTP 요청 객체
346380 * @return 액세스 토큰 값 또는 null
347381 */
0 commit comments