mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-01-13 08:58:48 +00:00
recovery del pass hecho en el backend a falta de hacer los formularios
This commit is contained in:
@ -0,0 +1,86 @@
|
||||
package com.imprimelibros.erp.auth;
|
||||
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.imprimelibros.erp.users.UserDao;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HexFormat;
|
||||
|
||||
@Service
|
||||
public class PasswordResetService {
|
||||
|
||||
private final PasswordResetTokenRepository tokenRepo;
|
||||
private final UserDao userRepo; // tu repo real
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
private static final SecureRandom RNG = new SecureRandom();
|
||||
private static final HexFormat HEX = HexFormat.of();
|
||||
|
||||
public PasswordResetService(PasswordResetTokenRepository tokenRepo, UserDao userRepo, PasswordEncoder enc) {
|
||||
this.tokenRepo = tokenRepo;
|
||||
this.userRepo = userRepo;
|
||||
this.passwordEncoder = enc;
|
||||
}
|
||||
|
||||
/** Elimina tokens previos sin usar, genera uno nuevo y lo guarda con auditoría básica. */
|
||||
public String createTokenForUser(Long userId, int hoursToExpire, String requestIp, String userAgent) {
|
||||
// Invalidar anteriores
|
||||
tokenRepo.deleteAllByUserIdAndUsedAtIsNull(userId);
|
||||
|
||||
// Generar token
|
||||
byte[] raw = new byte[32];
|
||||
RNG.nextBytes(raw);
|
||||
String token = HEX.formatHex(raw); // token plano (64 hex)
|
||||
String tokenHash = sha256(token);
|
||||
|
||||
PasswordResetToken prt = new PasswordResetToken();
|
||||
prt.setUserId(userId);
|
||||
prt.setTokenHash(tokenHash);
|
||||
prt.setExpiresAt(Instant.now().plus(hoursToExpire, ChronoUnit.HOURS));
|
||||
prt.setRequestIp(truncate(requestIp, 64));
|
||||
prt.setUserAgent(truncate(userAgent, 255));
|
||||
tokenRepo.save(prt);
|
||||
|
||||
return token; // Esto se envía por email
|
||||
}
|
||||
|
||||
public Long validateTokenAndGetUserId(String tokenPlain) {
|
||||
return tokenRepo.findByTokenHashAndUsedAtIsNullAndExpiresAtAfter(sha256(tokenPlain), Instant.now())
|
||||
.map(PasswordResetToken::getUserId)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public void consumeTokenAndSetPassword(String tokenPlain, String newPassword) {
|
||||
var tokenOpt = tokenRepo.findByTokenHashAndUsedAtIsNullAndExpiresAtAfter(sha256(tokenPlain), Instant.now());
|
||||
var prt = tokenOpt.orElseThrow(() -> new IllegalArgumentException("Token inválido o caducado"));
|
||||
|
||||
var user = userRepo.findById(prt.getUserId())
|
||||
.orElseThrow(() -> new IllegalStateException("Usuario no encontrado"));
|
||||
|
||||
user.setPassword(passwordEncoder.encode(newPassword));
|
||||
userRepo.save(user);
|
||||
|
||||
prt.setUsedAt(Instant.now());
|
||||
tokenRepo.save(prt);
|
||||
}
|
||||
|
||||
private static String sha256(String s) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
return HEX.formatHex(md.digest(s.getBytes(StandardCharsets.UTF_8)));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String truncate(String v, int max) {
|
||||
if (v == null) return null;
|
||||
return v.length() <= max ? v : v.substring(0, max);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user