feat(auth): add password reset functionality and DTO
This commit is contained in:
parent
9827f81230
commit
c8f2d16f07
8 changed files with 55 additions and 11 deletions
|
@ -4,6 +4,7 @@ import de.szut.casino.exceptionHandling.ErrorDetails;
|
||||||
import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException;
|
import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException;
|
||||||
import de.szut.casino.security.dto.AuthResponseDto;
|
import de.szut.casino.security.dto.AuthResponseDto;
|
||||||
import de.szut.casino.security.dto.LoginRequestDto;
|
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.security.service.AuthService;
|
||||||
import de.szut.casino.user.dto.CreateUserDto;
|
import de.szut.casino.user.dto.CreateUserDto;
|
||||||
import de.szut.casino.user.dto.GetUserDto;
|
import de.szut.casino.user.dto.GetUserDto;
|
||||||
|
@ -49,4 +50,10 @@ public class AuthController {
|
||||||
authService.recoverPassword(email);
|
authService.recoverPassword(email);
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/reset-password")
|
||||||
|
public ResponseEntity<Void> resetPassword(@Valid @RequestBody ResetPasswordDto passwordDto) throws MessagingException, IOException {
|
||||||
|
authService.resetPassword(passwordDto);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -3,17 +3,20 @@ package de.szut.casino.security.service;
|
||||||
import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException;
|
import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException;
|
||||||
import de.szut.casino.security.dto.AuthResponseDto;
|
import de.szut.casino.security.dto.AuthResponseDto;
|
||||||
import de.szut.casino.security.dto.LoginRequestDto;
|
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.security.jwt.JwtUtils;
|
||||||
import de.szut.casino.user.UserEntity;
|
import de.szut.casino.user.UserEntity;
|
||||||
import de.szut.casino.user.UserService;
|
import de.szut.casino.user.UserService;
|
||||||
import de.szut.casino.user.dto.CreateUserDto;
|
import de.szut.casino.user.dto.CreateUserDto;
|
||||||
import de.szut.casino.user.dto.GetUserDto;
|
import de.szut.casino.user.dto.GetUserDto;
|
||||||
import jakarta.mail.MessagingException;
|
import jakarta.mail.MessagingException;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.swing.text.html.Option;
|
import javax.swing.text.html.Option;
|
||||||
|
@ -35,6 +38,9 @@ public class AuthService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmailService emailService;
|
private EmailService emailService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
public AuthResponseDto login(LoginRequestDto loginRequest) throws EmailNotVerifiedException {
|
public AuthResponseDto login(LoginRequestDto loginRequest) throws EmailNotVerifiedException {
|
||||||
if (!userService.isVerified(loginRequest.getUsernameOrEmail())) {
|
if (!userService.isVerified(loginRequest.getUsernameOrEmail())) {
|
||||||
throw new EmailNotVerifiedException();
|
throw new EmailNotVerifiedException();
|
||||||
|
@ -81,15 +87,25 @@ public class AuthService {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recoverPassword(String email) {
|
public void recoverPassword(String email) throws MessagingException, IOException {
|
||||||
Optional<UserEntity> optionalUser = userService.getUserByEmail(email);
|
Optional<UserEntity> optionalUser = userService.getUserByEmail(email);
|
||||||
|
|
||||||
if (optionalUser.isPresent()) {
|
if (optionalUser.isPresent()) {
|
||||||
UserEntity user = optionalUser.get();
|
UserEntity user = optionalUser.get();
|
||||||
String token = jwtUtils.generateToken(user.getUsername());
|
user.setPasswordResetToken(RandomStringUtils.randomAlphanumeric(64));
|
||||||
user.setVerificationToken(token);
|
|
||||||
userService.saveUser(user);
|
userService.saveUser(user);
|
||||||
this.emailService.sendPasswordRecoveryEmail(user);
|
this.emailService.sendPasswordRecoveryEmail(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resetPassword(ResetPasswordDto passwordDto) {
|
||||||
|
Optional<UserEntity> optionalUser = userService.getUserByPasswordResetToken(passwordDto.getToken());
|
||||||
|
|
||||||
|
if (optionalUser.isPresent()) {
|
||||||
|
UserEntity user = optionalUser.get();
|
||||||
|
user.setPassword(passwordEncoder.encode(passwordDto.getPassword()));
|
||||||
|
user.setPasswordResetToken(null);
|
||||||
|
userService.saveUser(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,7 @@ public class EmailService {
|
||||||
String template = loadTemplate("email/recover-password.html");
|
String template = loadTemplate("email/recover-password.html");
|
||||||
String htmlContent = template
|
String htmlContent = template
|
||||||
.replace("${username}", user.getUsername())
|
.replace("${username}", user.getUsername())
|
||||||
|
.replace("${resetToken}", user.getPasswordResetToken())
|
||||||
.replace("${feUrl}", feUrl);
|
.replace("${feUrl}", feUrl);
|
||||||
|
|
||||||
MimeMessage message = mailSender.createMimeMessage();
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
|
|
@ -34,6 +34,8 @@ public class UserEntity {
|
||||||
|
|
||||||
private String verificationToken;
|
private String verificationToken;
|
||||||
|
|
||||||
|
private String passwordResetToken;
|
||||||
|
|
||||||
public UserEntity(String email, String username, String password, BigDecimal balance, String verificationToken) {
|
public UserEntity(String email, String username, String password, BigDecimal balance, String verificationToken) {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
|
|
|
@ -21,4 +21,7 @@ public interface UserRepository extends JpaRepository<UserEntity, Long> {
|
||||||
|
|
||||||
@Query("SELECT u FROM UserEntity u WHERE u.username = ?1 OR u.email = ?1")
|
@Query("SELECT u FROM UserEntity u WHERE u.username = ?1 OR u.email = ?1")
|
||||||
Optional<UserEntity> findOneByUsernameOrEmail(String usernameOrEmail);
|
Optional<UserEntity> findOneByUsernameOrEmail(String usernameOrEmail);
|
||||||
|
|
||||||
|
@Query("SELECT u FROM UserEntity u WHERE u.passwordResetToken = ?1")
|
||||||
|
Optional<UserEntity> findOneByPasswordResetToken(String token);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,4 +66,8 @@ public class UserService {
|
||||||
public Optional<UserEntity> getUserByEmail(String email) {
|
public Optional<UserEntity> getUserByEmail(String email) {
|
||||||
return userRepository.findByEmail(email);
|
return userRepository.findByEmail(email);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<UserEntity> getUserByPasswordResetToken(String token) {
|
||||||
|
return this.userRepository.findOneByPasswordResetToken(token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,12 +129,8 @@
|
||||||
<a href="${feUrl}/reset-password?token=${resetToken}" class="button">Passwort zurücksetzen</a>
|
<a href="${feUrl}/reset-password?token=${resetToken}" class="button">Passwort zurücksetzen</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>Alternativ können Sie auch diesen Code verwenden:</p>
|
|
||||||
|
|
||||||
<div class="recovery-code">${resetCode}</div>
|
|
||||||
|
|
||||||
<div class="info-box">
|
<div class="info-box">
|
||||||
<p><span class="warning">Hinweis:</span> Dieser Link und Code sind aus Sicherheitsgründen nur <span class="highlight">60 Minuten</span> gültig.</p>
|
<p><span class="warning">Hinweis:</span> Dieser Link und Code sind aus Sicherheitsgründen vielleicht nur <span class="highlight">60 Minuten</span> gültig.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
@ -145,15 +141,15 @@
|
||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<p>Bei Fragen steht Ihnen unser Support-Team jederzeit zur Verfügung.</p>
|
<p>Bei Fragen steht Ihnen unser Support-Team nicht zur Verfügung.</p>
|
||||||
|
|
||||||
<p>Mit freundlichen Grüßen,<br>
|
<p>Mit freundlichen Grüßen,<br>
|
||||||
Ihr <span style="color: #10b981;">Trustworthy Casino</span> Team</p>
|
Ihr <span style="color: #10b981;">Trustworthy Casino</span> Team</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<p>2025 Trustworthy Casino - Alle Rechte vorbehalten</p>
|
<p>2025 Trustworthy Casino - Keine Rechte vorbehalten</p>
|
||||||
<p>Diese E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.</p>
|
<p>Diese E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.</p>
|
||||||
<p>Für Fragen zur Sicherheit Ihres Kontos kontaktieren Sie uns bitte unter <span style="color: #10b981;">security@trustworthycasino.com</span></p>
|
<p>Für Fragen zur Sicherheit Ihres Kontos kontaktieren Sie uns bitte nicht.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
Reference in a new issue