mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-01-13 00:48:49 +00:00
trabajando en el registro de usuarios
This commit is contained in:
@ -124,6 +124,7 @@ public class SecurityConfig {
|
||||
.requestMatchers(
|
||||
"/",
|
||||
"/login",
|
||||
"/signup",
|
||||
"/assets/**",
|
||||
"/css/**",
|
||||
"/js/**",
|
||||
|
||||
@ -15,5 +15,11 @@ public class LoginController {
|
||||
return "imprimelibros/login/login";
|
||||
}
|
||||
|
||||
@GetMapping("/signup")
|
||||
public String signup(Model model, Locale locale) {
|
||||
model.addAttribute("form", "_signup");
|
||||
return "imprimelibros/login/login";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
97
src/main/java/com/imprimelibros/erp/login/SignupService.java
Normal file
97
src/main/java/com/imprimelibros/erp/login/SignupService.java
Normal file
@ -0,0 +1,97 @@
|
||||
package com.imprimelibros.erp.login;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
|
||||
import com.imprimelibros.erp.common.email.EmailService;
|
||||
import com.imprimelibros.erp.login.dto.SignupForm;
|
||||
import com.imprimelibros.erp.users.User;
|
||||
import com.imprimelibros.erp.users.UserDao;
|
||||
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
@Service
|
||||
public class SignupService {
|
||||
|
||||
private final UserDao userRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final VerificationTokenRepository tokenRepository;
|
||||
private final EmailService emailService;
|
||||
|
||||
// minutos de validez del token
|
||||
private static final long TOKEN_MINUTES = 60;
|
||||
|
||||
public SignupService(UserDao userRepository,
|
||||
PasswordEncoder passwordEncoder,
|
||||
VerificationTokenRepository tokenRepository,
|
||||
EmailService emailService) {
|
||||
this.userRepository = userRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.tokenRepository = tokenRepository;
|
||||
this.emailService = emailService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void register(SignupForm form) {
|
||||
if (!form.getPassword().equals(form.getPasswordConfirm())) {
|
||||
throw new IllegalArgumentException("Las contraseñas no coinciden");
|
||||
}
|
||||
|
||||
if (userRepository.existsByUsername(form.getUsername())) {
|
||||
throw new IllegalArgumentException("El correo ya está registrado");
|
||||
}
|
||||
|
||||
// Crear usuario deshabilitado
|
||||
User user = new User();
|
||||
user.setUsername(form.getUsername().trim().toLowerCase());
|
||||
user.setPassword(passwordEncoder.encode(form.getPassword()));
|
||||
user.setEnabled(false);
|
||||
// TODO: asignar rol por defecto si aplica (e.g., ROLE_USER)
|
||||
user = userRepository.save(user);
|
||||
|
||||
// Generar token
|
||||
var token = VerificationToken.create(user.getId(), TOKEN_MINUTES);
|
||||
tokenRepository.save(token);
|
||||
|
||||
// Construir URL absoluta para /verify
|
||||
String verifyUrl = ServletUriComponentsBuilder.fromCurrentContextPath()
|
||||
.path("/verify")
|
||||
.queryParam("token", token.getToken())
|
||||
.build()
|
||||
.toUriString();
|
||||
|
||||
// Enviar correo
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
model.put("verifyUrl", verifyUrl);
|
||||
model.put("minutes", TOKEN_MINUTES);
|
||||
emailService.sendTemplate(
|
||||
user.getUsername(),
|
||||
"Confirma tu correo | ImprimeLibros ERP",
|
||||
"mail/verify-email",
|
||||
model);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean verify(String tokenValue) {
|
||||
var tokenOpt = tokenRepository.findByToken(tokenValue);
|
||||
if (tokenOpt.isEmpty()) return false;
|
||||
|
||||
var token = tokenOpt.get();
|
||||
if (token.isUsed() || token.isExpired()) return false;
|
||||
|
||||
var user = userRepository.findById(token.getUserId())
|
||||
.orElseThrow(() -> new IllegalStateException("Usuario no encontrado para el token"));
|
||||
|
||||
user.setEnabled(true);
|
||||
userRepository.save(user);
|
||||
|
||||
token.setUsedAt(java.time.LocalDateTime.now());
|
||||
tokenRepository.save(token);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.imprimelibros.erp.login;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "verification_tokens", indexes = {
|
||||
@Index(name = "idx_verification_token_token", columnList = "token", unique = true)
|
||||
})
|
||||
public class VerificationToken {
|
||||
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable=false, unique=true, length=64)
|
||||
private String token;
|
||||
|
||||
@Column(nullable=false)
|
||||
private Long userId;
|
||||
|
||||
@Column(nullable=false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column(nullable=false)
|
||||
private LocalDateTime expiresAt;
|
||||
|
||||
private LocalDateTime usedAt;
|
||||
|
||||
public static VerificationToken create(Long userId, long minutesValid) {
|
||||
VerificationToken t = new VerificationToken();
|
||||
t.token = UUID.randomUUID().toString().replace("-", "");
|
||||
t.userId = userId;
|
||||
t.createdAt = LocalDateTime.now();
|
||||
t.expiresAt = t.createdAt.plusMinutes(minutesValid);
|
||||
return t;
|
||||
}
|
||||
|
||||
// getters/setters
|
||||
public Long getId() { return id; }
|
||||
public String getToken() { return token; }
|
||||
public void setToken(String token) { this.token = token; }
|
||||
public Long getUserId() { return userId; }
|
||||
public void setUserId(Long userId) { this.userId = userId; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public LocalDateTime getExpiresAt() { return expiresAt; }
|
||||
public void setExpiresAt(LocalDateTime expiresAt) { this.expiresAt = expiresAt; }
|
||||
public LocalDateTime getUsedAt() { return usedAt; }
|
||||
public void setUsedAt(LocalDateTime usedAt) { this.usedAt = usedAt; }
|
||||
|
||||
public boolean isUsed() { return usedAt != null; }
|
||||
public boolean isExpired() { return LocalDateTime.now().isAfter(expiresAt); }
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package com.imprimelibros.erp.login;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface VerificationTokenRepository extends JpaRepository<VerificationToken, Long> {
|
||||
Optional<VerificationToken> findByToken(String token);
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.imprimelibros.erp.login.dto;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
public class SignupForm {
|
||||
@NotBlank @Email
|
||||
private String username;
|
||||
|
||||
@NotBlank @Size(min = 8, message = "La contraseña debe tener al menos 8 caracteres")
|
||||
private String password;
|
||||
|
||||
@NotBlank
|
||||
private String passwordConfirm;
|
||||
|
||||
// getters/setters
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String u) { this.username = u; }
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String p) { this.password = p; }
|
||||
public String getPasswordConfirm() { return passwordConfirm; }
|
||||
public void setPasswordConfirm(String pc) { this.passwordConfirm = pc; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user