diff --git a/src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/request/FindPasswordRequest.java b/src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/request/FindPasswordRequest.java new file mode 100644 index 00000000..340c6247 --- /dev/null +++ b/src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/request/FindPasswordRequest.java @@ -0,0 +1,12 @@ +package org.ezcode.codetest.application.usermanagement.auth.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@Schema(description = "비밀번호 찾기 요청") +public class FindPasswordRequest { + private String email; +} diff --git a/src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/response/FindPasswordResponse.java b/src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/response/FindPasswordResponse.java new file mode 100644 index 00000000..34ed31f9 --- /dev/null +++ b/src/main/java/org/ezcode/codetest/application/usermanagement/auth/dto/response/FindPasswordResponse.java @@ -0,0 +1,9 @@ +package org.ezcode.codetest.application.usermanagement.auth.dto.response; + +public record FindPasswordResponse( + String message +) { + public static FindPasswordResponse from(String message) { + return new FindPasswordResponse(message); + } +} diff --git a/src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java b/src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java index 0510162f..d4b0683c 100644 --- a/src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java +++ b/src/main/java/org/ezcode/codetest/application/usermanagement/auth/service/AuthService.java @@ -3,7 +3,9 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import org.ezcode.codetest.application.usermanagement.auth.dto.request.FindPasswordRequest; import org.ezcode.codetest.application.usermanagement.auth.dto.request.VerifyEmailCodeRequest; +import org.ezcode.codetest.application.usermanagement.auth.dto.response.FindPasswordResponse; import org.ezcode.codetest.application.usermanagement.auth.dto.response.RefreshTokenResponse; import org.ezcode.codetest.application.usermanagement.auth.dto.request.SigninRequest; import org.ezcode.codetest.application.usermanagement.auth.dto.response.SendEmailCodeResponse; @@ -99,15 +101,16 @@ private void updateExistingUser(User existUser, String encodedPassword) { @Transactional public SendEmailCodeResponse sendEmailCode(Long userId, String email) { - mailService.sendMail(userId, email); + mailService.sendButtonMail(userId, email); return SendEmailCodeResponse.from("인증 코드를 전송했습니다."); } @Transactional - public VerifyEmailCodeResponse verifyEmailCode(Long userId, VerifyEmailCodeRequest verifyEmailCodeRequest) { - boolean isMatch = mailService.verifyCode(userId, verifyEmailCodeRequest.getVerificationCode()); + public VerifyEmailCodeResponse verifyEmailCode(String email, String key) { + User user = userDomainService.getUserByEmail(email); + + boolean isMatch = mailService.verifyCode(user.getId(), key); - User user = userDomainService.getUserById(userId); if (isMatch){ user.setVerified(); return VerifyEmailCodeResponse.from("인증되었습니다"); @@ -202,9 +205,43 @@ public RefreshTokenResponse refreshToken(String token) { User user = userDomainService.getUserById(userId); - String newAccessToken = createAccessToken(user); + String newAccessToken = jwtUtil.createAccessToken( + user.getId(), + user.getEmail(), + user.getRole(), + user.getUsername(), + user.getNickname(), + user.getTier() + ); return RefreshTokenResponse.from(newAccessToken); } + //비밀번호 찾기 메일 전송 + @Transactional + public FindPasswordResponse findPassword(FindPasswordRequest request) { + + User user = userDomainService.getUserByEmail(request.getEmail()); + if(user == null || user.isDeleted()){ + throw new AuthException(AuthExceptionCode.USER_NOT_FOUND); + } + + mailService.sendPasswordMail(user.getId(), request.getEmail()); + + return FindPasswordResponse.from("이메일로 전송되었습니다."); + } + + //메일로 받은 링크를 통해 비번 변경 + public FindPasswordResponse changePasswordByEmail(String email, String key) { + + User user = userDomainService.getUserByEmail(email); + + boolean isMatch = mailService.verifyCode(user.getId(), key); + + if (isMatch){ + return FindPasswordResponse.from("인증되었습니다"); + } else { + throw new UserException(UserExceptionCode.NOT_MATCH_CODE); + } + } } diff --git a/src/main/java/org/ezcode/codetest/common/security/config/SecurityConfig.java b/src/main/java/org/ezcode/codetest/common/security/config/SecurityConfig.java index 60fa86b1..5c25cde2 100644 --- a/src/main/java/org/ezcode/codetest/common/security/config/SecurityConfig.java +++ b/src/main/java/org/ezcode/codetest/common/security/config/SecurityConfig.java @@ -1,5 +1,7 @@ package org.ezcode.codetest.common.security.config; +import java.util.List; + import org.ezcode.codetest.common.security.util.SecurityPath; import org.ezcode.codetest.domain.user.service.CustomOAuth2UserService; import org.ezcode.codetest.common.security.hander.CustomSuccessHandler; @@ -10,6 +12,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -20,6 +23,9 @@ import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import jakarta.servlet.DispatcherType; import jakarta.servlet.http.HttpServletResponse; @@ -42,6 +48,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti return http // CSRF, Form 로그인, HTTP Basic 인증 비활성화 + .cors(Customizer.withDefaults()) // CORS 설정 추가 .csrf(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) @@ -121,5 +128,20 @@ public AccessDeniedHandler customAccessDeniedHandler() { }; } + //CORS 설정 추가 + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + + configuration.setAllowedOrigins(List.of("*")); // 다 허용 + configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); + configuration.setAllowedHeaders(List.of("*")); + configuration.setAllowCredentials(false); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + } diff --git a/src/main/java/org/ezcode/codetest/domain/user/service/MailService.java b/src/main/java/org/ezcode/codetest/domain/user/service/MailService.java index d6164870..a9d7f80f 100644 --- a/src/main/java/org/ezcode/codetest/domain/user/service/MailService.java +++ b/src/main/java/org/ezcode/codetest/domain/user/service/MailService.java @@ -23,21 +23,82 @@ public class MailService { @Value("${spring.mail.username}") private String senderEmail; - private static final long EXPIRATION_MINUTES = 3; + private static final long EXPIRATION_MINUTES = 10; - public void sendMail(Long userId, String mail) { - MimeMessage message = CreateMail(userId, mail); + public void sendCodeMail(Long userId, String email) { + MimeMessage message = CreateMail(userId, email); javaMailSender.send(message); } + public void sendButtonMail(Long userId, String email) { + MimeMessage message = CreateButtonMail(userId, email); + javaMailSender.send(message); + } + + public void sendPasswordMail(Long userId, String email) { + MimeMessage message = CreatePasswordMail(userId, email); + javaMailSender.send(message); + } + + public MimeMessage CreateButtonMail(Long userId, String email) { + MimeMessage message = javaMailSender.createMimeMessage(); + String key = createNumber(userId); //radis에 유저id&코드로 저장 (10분) + + try { + message.setFrom(senderEmail); + message.setRecipients(MimeMessage.RecipientType.TO, email); + message.setSubject("EZcode 이메일 인증"); + String body = ""; + body += "