diff --git a/src/main/kotlin/com/psr/psr/global/config/WebSecurityConfig.kt b/src/main/kotlin/com/psr/psr/global/config/WebSecurityConfig.kt index 97b4312..f087090 100644 --- a/src/main/kotlin/com/psr/psr/global/config/WebSecurityConfig.kt +++ b/src/main/kotlin/com/psr/psr/global/config/WebSecurityConfig.kt @@ -48,6 +48,7 @@ class WebSecurityConfig( c.requestMatchers("/users/nickname").permitAll() c.requestMatchers("/users/eid").permitAll() c.requestMatchers("/users/reissue").permitAll() + c.requestMatchers("/users/password-reset").permitAll() c.anyRequest().authenticated() } .apply(JwtSecurityConfig(jwtUtils, redisTemplate)) diff --git a/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt b/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt index 8dcbb06..af6d0ca 100644 --- a/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt +++ b/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt @@ -20,9 +20,11 @@ enum class BaseResponseCode(status: HttpStatus, message: String) { NOT_EXIST_EMAIL(HttpStatus.BAD_REQUEST, "해당 이메일로 가입한 사용자를 찾을 수 없습니다."), INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "사용자의 비밀번호가 일치하지 않습니다."), NOT_FOUND_USER(HttpStatus.NOT_FOUND, "사용자를 찾을 수 없습니다."), + INVALID_PHONE(HttpStatus.BAD_REQUEST, "사용자의 휴대폰 번호와 일치하지 않습니다."), NOT_FOUND_EID(HttpStatus.NOT_FOUND, "사업자를 찾을 수 없습니다."), NOT_EMPTY_EID(HttpStatus.BAD_REQUEST, "사업자 정보를 입력해주세요. "), INVALID_EID(HttpStatus.BAD_REQUEST, "정상 사업자가 아닙니다. (휴업자 or 폐업자)"), + DUPLICATE_PASSWORD(HttpStatus.BAD_REQUEST, "사용자의 비밀번호와 변경하려는 비밀번호가 동일합니다."), // User - type INVALID_USER_TYPE_NAME(HttpStatus.BAD_REQUEST, "올바르지 않은 사용자 역할입니다."), diff --git a/src/main/kotlin/com/psr/psr/user/controller/UserController.kt b/src/main/kotlin/com/psr/psr/user/controller/UserController.kt index c704286..a426f5d 100644 --- a/src/main/kotlin/com/psr/psr/user/controller/UserController.kt +++ b/src/main/kotlin/com/psr/psr/user/controller/UserController.kt @@ -114,5 +114,25 @@ class UserController( return BaseResponse(userService.reissueToken(tokenDto)) } + /** + * 비밀번호 변경화면 with Token + */ + @PatchMapping("/password-change") + @ResponseBody + fun changePassword(@AuthenticationPrincipal userAccount: UserAccount, @RequestBody @Validated passwordReq: ChangePasswordReq) : BaseResponse{ + userService.changePassword(userAccount.getUser(), passwordReq) + return BaseResponse(BaseResponseCode.SUCCESS) + } + + /** + * 비밀번호 재설정 except Token + */ + @PatchMapping("/password-reset") + @ResponseBody + fun resetPassword(@RequestBody @Validated resetPasswordReq: ResetPasswordReq) : BaseResponse{ + userService.resetPassword(resetPasswordReq) + return BaseResponse(BaseResponseCode.SUCCESS) + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/dto/ChangePasswordReq.kt b/src/main/kotlin/com/psr/psr/user/dto/ChangePasswordReq.kt new file mode 100644 index 0000000..f8f1be2 --- /dev/null +++ b/src/main/kotlin/com/psr/psr/user/dto/ChangePasswordReq.kt @@ -0,0 +1,19 @@ +package com.psr.psr.user.dto + +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.Pattern + +data class ChangePasswordReq ( + @field:NotBlank + @field:Pattern( + regexp = "^.*(?=^.{8,15}\$)(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#\$%^&+=]).*\$", + message = "비밀번호를 숫자, 문자, 특수문자 포함 8~15자리 이내로 입력해주세요" + ) + val currentPassword: String, + @field:NotBlank + @field:Pattern( + regexp = "^.*(?=^.{8,15}\$)(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#\$%^&+=]).*\$", + message = "비밀번호를 숫자, 문자, 특수문자 포함 8~15자리 이내로 입력해주세요" + ) + val password: String +) \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/dto/ResetPasswordReq.kt b/src/main/kotlin/com/psr/psr/user/dto/ResetPasswordReq.kt new file mode 100644 index 0000000..464193e --- /dev/null +++ b/src/main/kotlin/com/psr/psr/user/dto/ResetPasswordReq.kt @@ -0,0 +1,23 @@ +package com.psr.psr.user.dto + +import jakarta.validation.constraints.Email +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.Pattern + +data class ResetPasswordReq ( + @field:NotBlank(message = "이메일을 입력해주세요.") + @field:Email(message = "올바르지 않은 이메일 형식입니다.") + val email: String, + @field:NotBlank(message = "휴대폰을 입력해주세요.") + @field:Pattern( + regexp = "^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})\$", + message = "올바르지 않은 휴대폰 형식입니다." + ) + val phone: String, + @field:NotBlank(message = "비밀번호를 입력해주세요.") + @field:Pattern( + regexp = "^.*(?=^.{8,15}\$)(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#\$%^&+=]).*\$", + message = "비밀번호를 숫자, 문자, 특수문자 포함 8~15자리 이내로 입력해주세요" + ) + val password: String +) \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/service/UserService.kt b/src/main/kotlin/com/psr/psr/user/service/UserService.kt index 913842c..f5f0b08 100644 --- a/src/main/kotlin/com/psr/psr/user/service/UserService.kt +++ b/src/main/kotlin/com/psr/psr/user/service/UserService.kt @@ -180,4 +180,28 @@ class UserService( // token 생성 return jwtUtils.createToken(authentication, user.type) } + + // 비밀번호 변경 + @Transactional + fun changePassword(user: User, passwordReq: ChangePasswordReq) { + // 현재 비밀번호 일치 여부 + if(!passwordEncoder.matches(passwordReq.currentPassword, user.password)) throw BaseException(INVALID_PASSWORD) + // 현재 비밀번호와 변경하려는 비밀번호 일치 여부 + if(passwordReq.currentPassword == passwordReq.password) throw BaseException(DUPLICATE_PASSWORD) + + // 비밀번호 변경 + user.password = passwordEncoder.encode(passwordReq.password) + userRepository.save(user) + } + + // 비밀번호 재설정 + fun resetPassword(passwordReq: ResetPasswordReq) { + val user = userRepository.findByEmail(passwordReq.email).orElseThrow{BaseException(NOT_EXIST_EMAIL)} + if(user.phone != passwordReq.phone) throw BaseException(INVALID_PHONE) + if(passwordEncoder.matches(passwordReq.password, user.password)) throw BaseException(DUPLICATE_PASSWORD) + + // 비밀번호 변경 + user.password = passwordEncoder.encode(passwordReq.password) + userRepository.save(user) + } } \ No newline at end of file