Passwort reset Web

This commit is contained in:
klaas 2025-11-08 13:20:10 +01:00
parent af021c7830
commit 90cc3a6963
8 changed files with 68 additions and 12 deletions

View File

@ -2,7 +2,6 @@ package it.boergmann.tkdApp.config;
import it.boergmann.tkdApp.security.CustomUserDetailsService; import it.boergmann.tkdApp.security.CustomUserDetailsService;
import it.boergmann.tkdApp.security.JwtAuthenticationFilter; import it.boergmann.tkdApp.security.JwtAuthenticationFilter;
import jakarta.servlet.Filter;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -36,8 +35,6 @@ public class SecurityConfig {
private final CustomUserDetailsService userDetailsService; private final CustomUserDetailsService userDetailsService;
private final JwtAuthenticationFilter jwtAuthFilter; private final JwtAuthenticationFilter jwtAuthFilter;
// 🧱 1. API Security (JWT, kein Redirect)
@Bean @Bean
@Order(1) @Order(1)
public SecurityFilterChain apiSecurity(HttpSecurity http) throws Exception { public SecurityFilterChain apiSecurity(HttpSecurity http) throws Exception {
@ -57,13 +54,12 @@ public class SecurityConfig {
return http.build(); return http.build();
} }
// 🌐 2. Web Security (Form Login)
@Bean @Bean
@Order(2) @Order(2)
public SecurityFilterChain webSecurity(HttpSecurity http) throws Exception { public SecurityFilterChain webSecurity(HttpSecurity http) throws Exception {
http http
.authorizeHttpRequests(authz -> authz .authorizeHttpRequests(authz -> authz
.requestMatchers("/login", "/register", "/css/**", "/js/**", "/reset-request").permitAll() .requestMatchers("/login", "/register", "/css/**", "/js/**", "/reset-request", "/password-reset", "/set-password").permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
) )
.formLogin(form -> form .formLogin(form -> form

View File

@ -1,10 +1,10 @@
package it.boergmann.tkdApp.controller.web; package it.boergmann.tkdApp.controller.web;
import it.boergmann.tkdApp.dto.PasswordConfirmRequest;
import it.boergmann.tkdApp.dto.PasswordResetRequest; import it.boergmann.tkdApp.dto.PasswordResetRequest;
import it.boergmann.tkdApp.dto.RegisterRequest; import it.boergmann.tkdApp.dto.RegisterRequest;
import it.boergmann.tkdApp.domain.AppUser;
import it.boergmann.tkdApp.domain.Role;
import it.boergmann.tkdApp.repository.AppUserRepository; import it.boergmann.tkdApp.repository.AppUserRepository;
import it.boergmann.tkdApp.repository.AppUserRoleRepository;
import it.boergmann.tkdApp.service.AppUserService; import it.boergmann.tkdApp.service.AppUserService;
import it.boergmann.tkdApp.service.MailService; import it.boergmann.tkdApp.service.MailService;
import jakarta.validation.Valid; import jakarta.validation.Valid;
@ -15,14 +15,13 @@ import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller @Controller
@RequiredArgsConstructor @RequiredArgsConstructor
public class UserController { public class UserController {
private final AppUserRepository userRepository; private final AppUserRepository userRepository;
private final AppUserService appUserService; private final AppUserService appUserService;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final AppUserRoleRepository appUserRoleRepository;
@GetMapping("/register") @GetMapping("/register")
public String showRegisterForm(Model model) { public String showRegisterForm(Model model) {
@ -43,8 +42,6 @@ public class UserController {
return "login"; // src/main/resources/templates/login.html return "login"; // src/main/resources/templates/login.html
} }
private final MailService mailService; // oder dein eigener Service
@GetMapping("/reset-request") @GetMapping("/reset-request")
public String showRequestForm(Model model) { public String showRequestForm(Model model) {
model.addAttribute("emailRequest", new PasswordResetRequest()); model.addAttribute("emailRequest", new PasswordResetRequest());
@ -57,4 +54,20 @@ public class UserController {
model.addAttribute("message", "Wenn ein Konto existiert, wurde eine Mail gesendet."); model.addAttribute("message", "Wenn ein Konto existiert, wurde eine Mail gesendet.");
return "password_reset_request"; return "password_reset_request";
} }
@GetMapping("/set-password")
public String setNewPassword(@RequestParam String token, Model model) {
if (userRepository.existsByResetToken(token)) {
model.addAttribute("token", token);
return "set-password";
} else {
return "error/password_reset_request_error";
}
}
@PostMapping("/set-password")
public String saveNewPassword(@RequestBody PasswordConfirmRequest request){
appUserService.confirmPasswordReset(request);
return "password-reset-confirmation";
}
} }

View File

@ -9,4 +9,5 @@ public class PasswordConfirmRequest {
private String token; private String token;
@NotBlank(message = "Passwort darf nicht leer sein") @NotBlank(message = "Passwort darf nicht leer sein")
private String newPassword; private String newPassword;
private String newPasswordRepeated;
} }

View File

@ -15,6 +15,7 @@ import java.util.UUID;
public interface AppUserRepository extends JpaRepository<AppUser, UUID> { public interface AppUserRepository extends JpaRepository<AppUser, UUID> {
boolean existsByUsername(String username); // 🔥 hier hinzufügen! boolean existsByUsername(String username); // 🔥 hier hinzufügen!
boolean existsByEmail(String email); boolean existsByEmail(String email);
boolean existsByResetToken(String token);
Optional<AppUser> findByUsername(String username); Optional<AppUser> findByUsername(String username);
Optional<AppUser> findByResetToken(String token); Optional<AppUser> findByResetToken(String token);
Optional<AppUser> findByEmailVerificationToken(String token); Optional<AppUser> findByEmailVerificationToken(String token);

View File

@ -88,7 +88,7 @@ public class AppUserService {
user.setResetExpires(LocalDateTime.now().plusHours(1)); user.setResetExpires(LocalDateTime.now().plusHours(1));
userRepository.save(user); userRepository.save(user);
String link = "https://tkdapp.de/reset-password?token=" + user.getResetToken(); String link = "http://localhost:8080/set-password?token=" + user.getResetToken();
mailService.sendMail( mailService.sendMail(

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Passwort zurücksetzen</title>
</head>
<body>
<h2>Fehler</h2>
<p>kein gültiges Reset-Token</p>
</body>
</html>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Passwort zurückgesetzt</title>
</head>
<body>
<h1>Passwort erfolgreich geändert</h1>
<form th:action="@{/login}" method="post" th:object="${confirmationRequest}">
<label>Benutzername: <input type="text" name="username"/></label><br/>
<label>Passwort: <input type="password" name="password"/></label><br/>
<button type="submit">Login</button>
</form>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Passwort zurücksetzen</title>
</head>
<body>
<h2>Passwort zurücksetzen</h2>
<form th:action="@{/set-password}" method="post" th:object="${passwordConfirmRequest}">
<label>Passwort: <input type="password" name="newPassword"/></label><br/>
<label>Noch einmal: <input type="password" name="newPasswordRepeated"/></label><br/>
<input type="hidden" value=th:text="${token}"/>
<button type="submit">Zurücksetzen anfordern</button>
</form>
<p th:if="${message}" th:text="${message}"></p>
</body>
</html>