From c8f2d16f076d04d64fbb8cbc2761a10bb1153d5e Mon Sep 17 00:00:00 2001 From: csimonis Date: Thu, 15 May 2025 12:15:33 +0200 Subject: [PATCH] feat(auth): add password reset functionality and DTO --- .../szut/casino/security/AuthController.java | 7 ++++++ .../casino/security/dto/ResetPasswordDto.java | 15 +++++++++++++ .../casino/security/service/AuthService.java | 22 ++++++++++++++++--- .../casino/security/service/EmailService.java | 1 + .../java/de/szut/casino/user/UserEntity.java | 2 ++ .../de/szut/casino/user/UserRepository.java | 3 +++ .../java/de/szut/casino/user/UserService.java | 4 ++++ .../templates/email/recover-password.html | 12 ++++------ 8 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 backend/src/main/java/de/szut/casino/security/dto/ResetPasswordDto.java diff --git a/backend/src/main/java/de/szut/casino/security/AuthController.java b/backend/src/main/java/de/szut/casino/security/AuthController.java index 5d8717e..d22de30 100644 --- a/backend/src/main/java/de/szut/casino/security/AuthController.java +++ b/backend/src/main/java/de/szut/casino/security/AuthController.java @@ -4,6 +4,7 @@ import de.szut.casino.exceptionHandling.ErrorDetails; import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException; import de.szut.casino.security.dto.AuthResponseDto; import de.szut.casino.security.dto.LoginRequestDto; +import de.szut.casino.security.dto.ResetPasswordDto; import de.szut.casino.security.service.AuthService; import de.szut.casino.user.dto.CreateUserDto; import de.szut.casino.user.dto.GetUserDto; @@ -49,4 +50,10 @@ public class AuthController { authService.recoverPassword(email); return ResponseEntity.ok().build(); } + + @PostMapping("/reset-password") + public ResponseEntity resetPassword(@Valid @RequestBody ResetPasswordDto passwordDto) throws MessagingException, IOException { + authService.resetPassword(passwordDto); + return ResponseEntity.ok().build(); + } } diff --git a/backend/src/main/java/de/szut/casino/security/dto/ResetPasswordDto.java b/backend/src/main/java/de/szut/casino/security/dto/ResetPasswordDto.java new file mode 100644 index 0000000..192d928 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/security/dto/ResetPasswordDto.java @@ -0,0 +1,15 @@ +package de.szut.casino.security.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class ResetPasswordDto { + private String token; + private String password; +} diff --git a/backend/src/main/java/de/szut/casino/security/service/AuthService.java b/backend/src/main/java/de/szut/casino/security/service/AuthService.java index 380b5e4..959a55a 100644 --- a/backend/src/main/java/de/szut/casino/security/service/AuthService.java +++ b/backend/src/main/java/de/szut/casino/security/service/AuthService.java @@ -3,17 +3,20 @@ package de.szut.casino.security.service; import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException; import de.szut.casino.security.dto.AuthResponseDto; import de.szut.casino.security.dto.LoginRequestDto; +import de.szut.casino.security.dto.ResetPasswordDto; import de.szut.casino.security.jwt.JwtUtils; import de.szut.casino.user.UserEntity; import de.szut.casino.user.UserService; import de.szut.casino.user.dto.CreateUserDto; import de.szut.casino.user.dto.GetUserDto; import jakarta.mail.MessagingException; +import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import javax.swing.text.html.Option; @@ -35,6 +38,9 @@ public class AuthService { @Autowired private EmailService emailService; + @Autowired + private PasswordEncoder passwordEncoder; + public AuthResponseDto login(LoginRequestDto loginRequest) throws EmailNotVerifiedException { if (!userService.isVerified(loginRequest.getUsernameOrEmail())) { throw new EmailNotVerifiedException(); @@ -81,15 +87,25 @@ public class AuthService { return true; } - public void recoverPassword(String email) { + public void recoverPassword(String email) throws MessagingException, IOException { Optional optionalUser = userService.getUserByEmail(email); if (optionalUser.isPresent()) { UserEntity user = optionalUser.get(); - String token = jwtUtils.generateToken(user.getUsername()); - user.setVerificationToken(token); + user.setPasswordResetToken(RandomStringUtils.randomAlphanumeric(64)); userService.saveUser(user); this.emailService.sendPasswordRecoveryEmail(user); } } + + public void resetPassword(ResetPasswordDto passwordDto) { + Optional optionalUser = userService.getUserByPasswordResetToken(passwordDto.getToken()); + + if (optionalUser.isPresent()) { + UserEntity user = optionalUser.get(); + user.setPassword(passwordEncoder.encode(passwordDto.getPassword())); + user.setPasswordResetToken(null); + userService.saveUser(user); + } + } } diff --git a/backend/src/main/java/de/szut/casino/security/service/EmailService.java b/backend/src/main/java/de/szut/casino/security/service/EmailService.java index b7a05b9..f276a3c 100644 --- a/backend/src/main/java/de/szut/casino/security/service/EmailService.java +++ b/backend/src/main/java/de/szut/casino/security/service/EmailService.java @@ -91,6 +91,7 @@ public class EmailService { String template = loadTemplate("email/recover-password.html"); String htmlContent = template .replace("${username}", user.getUsername()) + .replace("${resetToken}", user.getPasswordResetToken()) .replace("${feUrl}", feUrl); MimeMessage message = mailSender.createMimeMessage(); diff --git a/backend/src/main/java/de/szut/casino/user/UserEntity.java b/backend/src/main/java/de/szut/casino/user/UserEntity.java index 161ce52..2190867 100644 --- a/backend/src/main/java/de/szut/casino/user/UserEntity.java +++ b/backend/src/main/java/de/szut/casino/user/UserEntity.java @@ -34,6 +34,8 @@ public class UserEntity { private String verificationToken; + private String passwordResetToken; + public UserEntity(String email, String username, String password, BigDecimal balance, String verificationToken) { this.email = email; this.username = username; diff --git a/backend/src/main/java/de/szut/casino/user/UserRepository.java b/backend/src/main/java/de/szut/casino/user/UserRepository.java index 9eafd54..29790f5 100644 --- a/backend/src/main/java/de/szut/casino/user/UserRepository.java +++ b/backend/src/main/java/de/szut/casino/user/UserRepository.java @@ -21,4 +21,7 @@ public interface UserRepository extends JpaRepository { @Query("SELECT u FROM UserEntity u WHERE u.username = ?1 OR u.email = ?1") Optional findOneByUsernameOrEmail(String usernameOrEmail); + + @Query("SELECT u FROM UserEntity u WHERE u.passwordResetToken = ?1") + Optional findOneByPasswordResetToken(String token); } diff --git a/backend/src/main/java/de/szut/casino/user/UserService.java b/backend/src/main/java/de/szut/casino/user/UserService.java index a04b02e..baa2eab 100644 --- a/backend/src/main/java/de/szut/casino/user/UserService.java +++ b/backend/src/main/java/de/szut/casino/user/UserService.java @@ -66,4 +66,8 @@ public class UserService { public Optional getUserByEmail(String email) { return userRepository.findByEmail(email); } + + public Optional getUserByPasswordResetToken(String token) { + return this.userRepository.findOneByPasswordResetToken(token); + } } diff --git a/backend/src/main/resources/templates/email/recover-password.html b/backend/src/main/resources/templates/email/recover-password.html index 6d4e1a1..cf666d1 100644 --- a/backend/src/main/resources/templates/email/recover-password.html +++ b/backend/src/main/resources/templates/email/recover-password.html @@ -129,12 +129,8 @@ Passwort zurücksetzen -

Alternativ können Sie auch diesen Code verwenden:

- -
${resetCode}
-
-

Hinweis: Dieser Link und Code sind aus Sicherheitsgründen nur 60 Minuten gültig.

+

Hinweis: Dieser Link und Code sind aus Sicherheitsgründen vielleicht nur 60 Minuten gültig.

@@ -145,15 +141,15 @@
-

Bei Fragen steht Ihnen unser Support-Team jederzeit zur Verfügung.

+

Bei Fragen steht Ihnen unser Support-Team nicht zur Verfügung.

Mit freundlichen Grüßen,
Ihr Trustworthy Casino Team