From 08ad52110c1ccfb33597a0dc75dfda464ee1c5f7 Mon Sep 17 00:00:00 2001 From: dgjinsu Date: Sat, 19 Oct 2024 13:52:48 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=B0=BE=EA=B8=B0=20=EC=8B=9C=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=EC=9D=84=20=EB=B0=9B=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/MemberInfoController.java | 25 +++++++---- .../member/dto/info/PasswordFindResponse.java | 17 +++++++ .../member/repository/MemberRepository.java | 6 +++ .../member/service/MemberInfoService.java | 45 ++++++++++++++----- .../jikgong/global/exception/ErrorCode.java | 3 +- 5 files changed, 74 insertions(+), 22 deletions(-) create mode 100644 src/main/java/jikgong/domain/member/dto/info/PasswordFindResponse.java diff --git a/src/main/java/jikgong/domain/member/controller/MemberInfoController.java b/src/main/java/jikgong/domain/member/controller/MemberInfoController.java index c02eba8..ec22b3d 100644 --- a/src/main/java/jikgong/domain/member/controller/MemberInfoController.java +++ b/src/main/java/jikgong/domain/member/controller/MemberInfoController.java @@ -4,12 +4,13 @@ import io.swagger.v3.oas.annotations.Operation; import java.util.List; import jikgong.domain.member.dto.company.CompanySearchResponse; +import jikgong.domain.member.dto.info.AuthCodeForFindRequest; import jikgong.domain.member.dto.info.CompanyInfoRequest; import jikgong.domain.member.dto.info.CompanyInfoResponse; -import jikgong.domain.member.dto.info.LoginIdAuthCodeRequest; import jikgong.domain.member.dto.info.LoginIdFindRequest; import jikgong.domain.member.dto.info.LoginIdFindResponse; import jikgong.domain.member.dto.info.PasswordFindRequest; +import jikgong.domain.member.dto.info.PasswordFindResponse; import jikgong.domain.member.dto.info.PasswordUpdateRequest; import jikgong.domain.member.dto.info.WorkerInfoRequest; import jikgong.domain.member.dto.info.WorkerInfoResponse; @@ -84,24 +85,32 @@ public ResponseEntity updatePassword(@AuthenticationPrincipal Principa @Operation(summary = "아이디 찾기 전 본인 인증") @PostMapping("/api/member-info/loginId-verification") - public ResponseEntity verificationFindLoginId(@RequestBody LoginIdFindRequest request) { + public ResponseEntity verificationBeforeFindLoginId(@RequestBody LoginIdFindRequest request) { memberInfoService.verificationBeforeFindLoginId(request); return ResponseEntity.ok(new Response("아이디 찾기 인증 코드 발송 완료")); } @Operation(summary = "아이디 찾기", description = "본인 인증으로 발송된 authCode를 사용하여 아이디 찾기") @PostMapping("/api/member-info/loginId/retrieve") - public ResponseEntity findLoginId(@RequestBody LoginIdAuthCodeRequest request) { + public ResponseEntity findLoginId(@RequestBody AuthCodeForFindRequest request) { LoginIdFindResponse loginIdFindResponse = memberInfoService.findLoginId(request); return ResponseEntity.ok(new Response(loginIdFindResponse, "비밀번호 확인 완료")); } - @Operation(summary = "비밀번호 찾기 (임시 발급)", description = "sms로 임시 비밀번호 발급") - @PostMapping("/api/member-info/password-reset") - public ResponseEntity findPassword(@RequestBody PasswordFindRequest request) + @Operation(summary = "비밀번호 찾기 전 본인 인증") + @PostMapping("/api/member-info/password-verification") + public ResponseEntity verificationBeforeFindPassword(@RequestBody PasswordFindRequest request) throws Exception { - memberInfoService.sendTemporaryPassword(request); - return ResponseEntity.ok(new Response("sms로 임시 비밀번호 발급 및 비밀번호 업데이트 완료")); + memberInfoService.verificationBeforeFindPassword(request); + return ResponseEntity.ok(new Response("비밀번호 찾기 인증 코드 발송 완료")); + } + + @Operation(summary = "비밀번호 임시 발급", description = "문자 인증 코드 입력 후 임시 비밀번호 발급") + @PostMapping("/api/member-info/password-temporary") + public ResponseEntity updateTemporaryPassword(@RequestBody AuthCodeForFindRequest request) + throws Exception { + PasswordFindResponse passwordFindResponse = memberInfoService.updateTemporaryPassword(request); + return ResponseEntity.ok(new Response(passwordFindResponse, "임시 비밀번호로 업데이트 및 반환 완료")); } @Operation(summary = "체류 만료일 불러오기", description = "codef api를 활용하여 체류 만료일 정보 저장") diff --git a/src/main/java/jikgong/domain/member/dto/info/PasswordFindResponse.java b/src/main/java/jikgong/domain/member/dto/info/PasswordFindResponse.java new file mode 100644 index 0000000..c8f0924 --- /dev/null +++ b/src/main/java/jikgong/domain/member/dto/info/PasswordFindResponse.java @@ -0,0 +1,17 @@ +package jikgong.domain.member.dto.info; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class PasswordFindResponse { + + private String temporaryPassword; + + public static PasswordFindResponse from(String temporaryPassword) { + return PasswordFindResponse.builder() + .temporaryPassword(temporaryPassword) + .build(); + } +} diff --git a/src/main/java/jikgong/domain/member/repository/MemberRepository.java b/src/main/java/jikgong/domain/member/repository/MemberRepository.java index 8df73ca..5a36039 100644 --- a/src/main/java/jikgong/domain/member/repository/MemberRepository.java +++ b/src/main/java/jikgong/domain/member/repository/MemberRepository.java @@ -38,4 +38,10 @@ public interface MemberRepository extends JpaRepository { @Query("select m from Member m where m.phone = :phone and " + "(m.workerInfo.workerName = :name or m.companyInfo.companyName = :name)") Optional findMemberForForgottenLoginId(@Param("phone") String phone, @Param("name") String name); + + /** + * 비밀번호 찾기 + */ + @Query("select m from Member m where m.loginId = :loginId and m.phone = :phone") + Optional findMemberForForgottenPassword(@Param("loginId") String loginId, @Param("phone") String phone); } diff --git a/src/main/java/jikgong/domain/member/service/MemberInfoService.java b/src/main/java/jikgong/domain/member/service/MemberInfoService.java index 26ee414..0aa87c5 100644 --- a/src/main/java/jikgong/domain/member/service/MemberInfoService.java +++ b/src/main/java/jikgong/domain/member/service/MemberInfoService.java @@ -7,12 +7,13 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import jikgong.domain.member.dto.company.CompanySearchResponse; +import jikgong.domain.member.dto.info.AuthCodeForFindRequest; import jikgong.domain.member.dto.info.CompanyInfoRequest; import jikgong.domain.member.dto.info.CompanyInfoResponse; -import jikgong.domain.member.dto.info.LoginIdAuthCodeRequest; import jikgong.domain.member.dto.info.LoginIdFindRequest; import jikgong.domain.member.dto.info.LoginIdFindResponse; import jikgong.domain.member.dto.info.PasswordFindRequest; +import jikgong.domain.member.dto.info.PasswordFindResponse; import jikgong.domain.member.dto.info.PasswordUpdateRequest; import jikgong.domain.member.dto.info.WorkerInfoRequest; import jikgong.domain.member.dto.info.WorkerInfoResponse; @@ -145,24 +146,44 @@ public List searchCompany(String keyword) { } /** - * 임시 비밀번호 생성 + * 비밀번호 찾기 전 문자 인증 */ - public void sendTemporaryPassword(PasswordFindRequest request) throws Exception { - Member member = memberRepository.findByLoginId(request.getLoginId()) + public void verificationBeforeFindPassword(PasswordFindRequest request) throws Exception { + Member member = memberRepository.findMemberForForgottenPassword(request.getLoginId(), request.getPhone()) .orElseThrow(() -> new JikgongException(ErrorCode.MEMBER_NOT_FOUND)); - // 휴대폰 번호 확인 - if (member.getPhone().equals(request.getPhone())) { - throw new JikgongException(ErrorCode.MEMBER_PHONE_NOT_MATCH); + // 6자리 랜덤 코드 생성 + String authCode = RandomCode.createAuthCode(); + String content = "[직공]\n비밀번호 찾기 본인확인 인증번호: [" + authCode + "]"; + try { + smsService.sendSms(member.getPhone(), content); + } catch (Exception e) { + throw new JikgongException(ErrorCode.SMS_SEND_FAIL); + } + + // Redis에 인증 코드와 회원 정보를 저장 (TTL 5분) + redisTemplate.opsForValue().set(member.getPhone(), authCode, 5, TimeUnit.MINUTES); + } + + /** + * 임시 비밀번호 발급 + */ + public PasswordFindResponse updateTemporaryPassword(AuthCodeForFindRequest request) { + // Redis에 저장된 인증 코드 가져오기 + String savedAuthCode = redisTemplate.opsForValue().get(request.getPhone()); + + // 인증 코드가 일치하는지 체크 + if (savedAuthCode == null || !savedAuthCode.equals(request.getAuthCode())) { + throw new JikgongException(ErrorCode.MEMBER_INVALID_AUTH_CODE); // 인증 코드 불일치 } - // 임시 비밀번호 생성 + // 임시 번호 생성, 업데이트 및 반환 String temporaryPassword = RandomCode.createTemporaryPassword(); - String content = "[직공]\n발급된 임시 비밀번호: [" + temporaryPassword + "]"; + Member member = memberRepository.findByPhone(request.getPhone()) + .orElseThrow(() -> new JikgongException(ErrorCode.MEMBER_NOT_FOUND)); member.updatePassword(encoder.encode(temporaryPassword)); - // 임시 비밀번호 발송 - smsService.sendSms(member.getPhone(), content); + return PasswordFindResponse.from(temporaryPassword); } /** @@ -188,7 +209,7 @@ public void verificationBeforeFindLoginId(LoginIdFindRequest request) { /** * 문자로 인증된 코드로 아이디 찾기 */ - public LoginIdFindResponse findLoginId(LoginIdAuthCodeRequest request) { + public LoginIdFindResponse findLoginId(AuthCodeForFindRequest request) { // Redis에 저장된 인증 코드 가져오기 String savedAuthCode = redisTemplate.opsForValue().get(request.getPhone()); diff --git a/src/main/java/jikgong/global/exception/ErrorCode.java b/src/main/java/jikgong/global/exception/ErrorCode.java index 5aedd83..0b76c9a 100644 --- a/src/main/java/jikgong/global/exception/ErrorCode.java +++ b/src/main/java/jikgong/global/exception/ErrorCode.java @@ -21,8 +21,7 @@ public enum ErrorCode { MEMBER_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "MEMBER-009", "인증이 필요합니다."), MEMBER_FORBIDDEN(HttpStatus.FORBIDDEN, "MEMBER-010", "권한이 필요합니다."), MEMBER_CONSENTS_NEED_TO_AGREE(HttpStatus.FORBIDDEN, "MEMBER-011", "회원가입을 위해선 각종 내용에 동의해야합니다."), - MEMBER_PHONE_NOT_MATCH(HttpStatus.BAD_REQUEST, "MEMBER-012", "회원 정보에 입력된 핸드폰 번호와 일치하지 않습니다."), - MEMBER_INVALID_AUTH_CODE(HttpStatus.BAD_REQUEST, "MEMBER-013", "아이디를 찾기 위해 입력한 인증 코드가 올바르지 않습니다."), + MEMBER_INVALID_AUTH_CODE(HttpStatus.BAD_REQUEST, "MEMBER-012", "아이디를 찾기 위해 입력한 인증 코드가 올바르지 않습니다."), /** * 알림