-
Notifications
You must be signed in to change notification settings - Fork 1
[FEAT] 비밀번호 찾기 기능 구현 #110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
The head ref may contain hidden characters: "feat/#109/\uBE44\uBC00\uBC88\uD638-\uCC3E\uAE30-api-\uAE30\uB2A5-\uAD6C\uD604"
Merged
[FEAT] 비밀번호 찾기 기능 구현 #110
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
e0b27a4
chore: 개발 환경 ddl auto 설정 변경
KoungQ 04d0be2
fix: 이메일 인증 로직 수정
KoungQ 5f090bf
feat: 비밀번호 변경 시 이메일 인증 및 비밀번호 변경 로직 추가
KoungQ 112797c
fix: 불필요한 DI 제거
KoungQ bf9f075
fix: 캘린더 엔티티 수정
KoungQ 765d82b
fix: 비밀번호 입력값 제한
KoungQ d9c0247
fix: 비밀번호 변경 로직 수정
KoungQ 24e0de4
fix: 사용자 열거 공격 방어
KoungQ 3729f09
feat: 이메일 전송 로직 레이트리밋 추가
KoungQ e38de9a
fix: 회원가입 체류 시간 연장
KoungQ 9a03a51
fix: 이메일 전송 로직 검증
KoungQ 97eba3c
fix: Discord 웹훅 오류 분기 처리
KoungQ 194ca80
test: 기존 테스트 코드 수정
KoungQ ab9fd81
fix: CI 테스트 환경에 Redis 서비스 컨테이너 추가
KoungQ 4a17361
fix: 테스트 코드 수정
KoungQ File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 8 additions & 1 deletion
9
...om/project/dorumdorum/domain/calendar/application/dto/response/CalendarEventResponse.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,16 @@ | ||
| package com.project.dorumdorum.domain.calendar.application.dto.response; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||
| import com.project.dorumdorum.domain.calendar.domain.entity.CalendarEventType; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.time.LocalTime; | ||
|
|
||
| public record CalendarEventResponse( | ||
| LocalDate date, | ||
| String title | ||
| String title, | ||
| String content, | ||
| @JsonFormat(pattern = "HH:mm") LocalTime time, | ||
| CalendarEventType type | ||
| ) { | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
src/main/java/com/project/dorumdorum/domain/calendar/domain/entity/CalendarEventType.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.project.dorumdorum.domain.calendar.domain.entity; | ||
|
|
||
| public enum CalendarEventType { | ||
| CHECK, // 점호 | ||
| CLEAN, // 청소 | ||
| NOTICE, // 공지 | ||
| EVENT // 행사 | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
...java/com/project/dorumdorum/domain/user/application/dto/request/ResetPasswordRequest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.project.dorumdorum.domain.user.application.dto.request; | ||
|
|
||
| import jakarta.validation.constraints.Email; | ||
| import jakarta.validation.constraints.NotBlank; | ||
| import jakarta.validation.constraints.Pattern; | ||
| import jakarta.validation.constraints.Size; | ||
|
|
||
| public record ResetPasswordRequest( | ||
| @Email @NotBlank String email, | ||
| @NotBlank @Size(min = 8, message = "비밀번호는 8자 이상이어야 합니다.") @Pattern(regexp = "^[A-Za-z0-9!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]+$", message = "비밀번호는 영문, 숫자, 특수문자만 사용할 수 있습니다.") String newPassword, | ||
| @NotBlank String newPasswordCheck | ||
| ) { | ||
| public boolean isPasswordMatch() { | ||
| return newPassword.equals(newPasswordCheck); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
...ain/java/com/project/dorumdorum/domain/user/application/usecase/ResetPasswordUseCase.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package com.project.dorumdorum.domain.user.application.usecase; | ||
|
|
||
| import com.project.dorumdorum.domain.user.application.dto.request.ResetPasswordRequest; | ||
| import com.project.dorumdorum.domain.user.domain.entity.User; | ||
| import com.project.dorumdorum.domain.user.domain.repository.PasswordResetVerifiedRepository; | ||
| import com.project.dorumdorum.domain.user.domain.service.UserService; | ||
| import com.project.dorumdorum.global.exception.RestApiException; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.security.crypto.password.PasswordEncoder; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import static com.project.dorumdorum.global.exception.code.status.AuthErrorStatus.FAILED_EMAIL_VERIFICATION; | ||
| import static com.project.dorumdorum.global.exception.code.status.UserErrorStatus._PASSWORD_NOT_MATCHES; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class ResetPasswordUseCase { | ||
|
|
||
| private final UserService userService; | ||
| private final PasswordResetVerifiedRepository passwordResetVerifiedRepository; | ||
| private final PasswordEncoder passwordEncoder; | ||
|
|
||
| /** | ||
| * 비밀번호 재설정 | ||
| * - 비밀번호 일치 여부 확인 | ||
| * - 이메일 인증 완료 여부 확인 | ||
| * - 비밀번호 업데이트 | ||
| */ | ||
| @Transactional | ||
| public void execute(ResetPasswordRequest request) { | ||
| if (!request.isPasswordMatch()) { | ||
| throw new RestApiException(_PASSWORD_NOT_MATCHES); | ||
| } | ||
|
|
||
| if (!passwordResetVerifiedRepository.existsByEmail(request.email())) { | ||
| throw new RestApiException(FAILED_EMAIL_VERIFICATION); | ||
| } | ||
|
|
||
| User user = userService.findByEmail(request.email()); | ||
| user.updatePassword(passwordEncoder.encode(request.newPassword())); | ||
|
KoungQ marked this conversation as resolved.
|
||
| passwordResetVerifiedRepository.delete(request.email()); | ||
| } | ||
| } | ||
39 changes: 39 additions & 0 deletions
39
...com/project/dorumdorum/domain/user/application/usecase/SendPasswordResetEmailUseCase.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package com.project.dorumdorum.domain.user.application.usecase; | ||
|
|
||
| import com.project.dorumdorum.domain.user.domain.service.EmailVerificationService; | ||
| import com.project.dorumdorum.domain.user.domain.service.UserService; | ||
| import com.project.dorumdorum.global.exception.RestApiException; | ||
| import com.project.dorumdorum.global.ratelimit.RateLimited; | ||
| import com.project.dorumdorum.global.util.SecureRandomGenerator; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
|
|
||
| import static com.project.dorumdorum.global.exception.code.status.AuthErrorStatus.INVALID_EMAIL_DOMAIN; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class SendPasswordResetEmailUseCase { | ||
|
|
||
| private final UserService userService; | ||
| private final EmailVerificationService emailVerificationService; | ||
| private final SecureRandomGenerator secureRandomGenerator; | ||
|
|
||
| /** | ||
| * 비밀번호 재설정 인증 코드 발송 | ||
| * - 허용된 대학 이메일 도메인인지 검증 | ||
| * - 가입된 이메일인 경우에만 실제로 코드를 발송 (미가입 이메일도 동일한 200 응답 반환) | ||
| */ | ||
| @RateLimited(tag = "password-reset-email", key = "#email") | ||
| public void send(String email) { | ||
| if (!emailVerificationService.isAllowedUniversityEmail(email)) { | ||
| throw new RestApiException(INVALID_EMAIL_DOMAIN); | ||
| } | ||
|
|
||
| if (!userService.isAlreadyRegistered(email)) { | ||
| return; | ||
| } | ||
|
|
||
| String code = secureRandomGenerator.generate(); | ||
| emailVerificationService.sendCode(email, code); | ||
|
KoungQ marked this conversation as resolved.
|
||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
...om/project/dorumdorum/domain/user/application/usecase/VerifyPasswordResetCodeUseCase.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.project.dorumdorum.domain.user.application.usecase; | ||
|
|
||
| import com.project.dorumdorum.domain.user.domain.repository.PasswordResetVerifiedRepository; | ||
| import com.project.dorumdorum.domain.user.domain.service.EmailVerificationService; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class VerifyPasswordResetCodeUseCase { | ||
|
|
||
| private final PasswordResetVerifiedRepository passwordResetVerifiedRepository; | ||
| private final EmailVerificationService emailVerificationService; | ||
|
|
||
| /** | ||
| * 비밀번호 재설정 인증 코드 검증 | ||
| * - 인증 코드 일치 여부 확인 | ||
| * - 검증 성공 시 비밀번호 재설정 가능 상태를 Redis에 저장 | ||
| */ | ||
| public void execute(String email, String code) { | ||
| emailVerificationService.verifyCode(email, code); | ||
| passwordResetVerifiedRepository.save(email); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
...in/java/com/project/dorumdorum/domain/user/domain/repository/EmailVerifiedRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.project.dorumdorum.domain.user.domain.repository; | ||
|
|
||
| public interface EmailVerifiedRepository { | ||
|
|
||
| void save(String email); | ||
| boolean existsByEmail(String email); | ||
| void delete(String email); | ||
| } |
10 changes: 10 additions & 0 deletions
10
...ava/com/project/dorumdorum/domain/user/domain/repository/PasswordResetCodeRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.project.dorumdorum.domain.user.domain.repository; | ||
|
|
||
| import java.util.Optional; | ||
|
|
||
| public interface PasswordResetCodeRepository { | ||
|
|
||
| void save(String email, String code); | ||
| Optional<String> findByEmail(String email); | ||
| void delete(String email); | ||
| } |
8 changes: 8 additions & 0 deletions
8
...com/project/dorumdorum/domain/user/domain/repository/PasswordResetVerifiedRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.project.dorumdorum.domain.user.domain.repository; | ||
|
|
||
| public interface PasswordResetVerifiedRepository { | ||
|
|
||
| void save(String email); | ||
| boolean existsByEmail(String email); | ||
| void delete(String email); | ||
| } |
32 changes: 32 additions & 0 deletions
32
...ava/com/project/dorumdorum/domain/user/infra/repository/RedisEmailVerifiedRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package com.project.dorumdorum.domain.user.infra.repository; | ||
|
|
||
| import com.project.dorumdorum.domain.user.domain.repository.EmailVerifiedRepository; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.data.redis.core.RedisTemplate; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| import java.time.Duration; | ||
|
|
||
| @Repository | ||
| @RequiredArgsConstructor | ||
| public class RedisEmailVerifiedRepository implements EmailVerifiedRepository { | ||
|
|
||
| private final RedisTemplate<String, String> redisTemplate; | ||
| private static final String EMAIL_VERIFIED = "EMAIL_VERIFIED:"; | ||
| private static final String VERIFIED_VALUE = "verified"; | ||
|
|
||
| @Override | ||
| public void save(String email) { | ||
| redisTemplate.opsForValue().set(EMAIL_VERIFIED + email, VERIFIED_VALUE, Duration.ofMinutes(30)); | ||
| } | ||
|
KoungQ marked this conversation as resolved.
|
||
|
|
||
| @Override | ||
| public boolean existsByEmail(String email) { | ||
| return Boolean.TRUE.equals(redisTemplate.hasKey(EMAIL_VERIFIED + email)); | ||
| } | ||
|
|
||
| @Override | ||
| public void delete(String email) { | ||
| redisTemplate.delete(EMAIL_VERIFIED + email); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.