Commit 3c7dca7a by Rubén Ramírez

fix: [*]: Corregidos unos bugs detectados

parent 3c4635e0
package com.ujaen.tfg.mangaffinity.excepciones;
public class NombreUsuarioYaCogido extends RuntimeException {
}
package com.ujaen.tfg.mangaffinity.repositorios;
import com.ujaen.tfg.mangaffinity.entidades.Usuario;
import com.ujaen.tfg.mangaffinity.excepciones.NombreUsuarioYaCogido;
import com.ujaen.tfg.mangaffinity.excepciones.UsuarioYaRegistrado;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
......@@ -18,13 +19,26 @@ public class RepositorioUsuario {
public void guardar(Usuario usuario) {
if (!em.createQuery("select u from Usuario u where u.email = ?1", Usuario.class)
.setParameter(1, usuario.getEmail())
// Email no registrados
boolean emailExistente = !em.createQuery("SELECT u FROM Usuario u WHERE u.email = :email", Usuario.class)
.setParameter("email", usuario.getEmail())
.getResultList()
.isEmpty()) {
.isEmpty();
if (emailExistente) {
throw new UsuarioYaRegistrado();
}
//Nombre de usuario no utilizado
boolean nombreUsuarioExistente = !em.createQuery("SELECT u FROM Usuario u WHERE u.nombreUsuario = :nombreUsuario", Usuario.class)
.setParameter("nombreUsuario", usuario.getNombreUsuario())
.getResultList()
.isEmpty();
if (nombreUsuarioExistente) {
throw new NombreUsuarioYaCogido();
}
em.persist(usuario);
}
......
......@@ -6,7 +6,6 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public class DTOLoginRespuesta {
private String token;
private String email;
private String nombreUsuario;
......
......@@ -13,9 +13,7 @@ import lombok.Setter;
@NoArgsConstructor
@AllArgsConstructor
public class DTOUsuario {
private Long id = null; // Permitir que sea nulo al crear
private Long id = null; // Permito que sea nulo al crear
@Email
private String email;
......
......@@ -10,12 +10,12 @@ import javax.crypto.SecretKey;
@Component
public class JwtUtil {
// Clave secreta para firmar y verificar el token (debe ser la misma en todo el proyecto)
private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
private static final long EXPIRATION_TIME = 86400000; // 1 día en milisegundos
// Genera un token JWT con los datos proporcionados
// Genera un token JWT con los datos
public String generateToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
......@@ -26,7 +26,7 @@ public class JwtUtil {
.compact();
}
// Decodifica el JWT utilizando la misma clave secreta
// Decodifica el JWT
public Claims decodeJWT(String token) {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY) // Usamos la misma clave para decodificar
......@@ -35,23 +35,22 @@ public class JwtUtil {
.getBody();
}
// Extrae el nombre de usuario (subject) desde el token JWT
// Extrae el nombre de usuario
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
// Extrae la fecha de expiración del token
// Extrae la fecha de expiración
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
// Extrae un claim específico del token
// Extrae un claim específico
public <T> T extractClaim(String token, java.util.function.Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
// Validar si un token es correcto y no ha expirado
public boolean validateToken(String token, String username) {
final String extractedUsername = extractUsername(token);
return (extractedUsername.equals(username) && !isTokenExpired(token));
......
......@@ -3,13 +3,12 @@ package com.ujaen.tfg.mangaffinity.seguridad;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
@Configuration
@EnableWebSecurity
......
......@@ -18,15 +18,12 @@ import java.util.Optional;
@Service
public class ServicioUsuarios {
@Autowired
RepositorioUsuario repositorioUsuario;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private JwtUtil jwtUtil;
......@@ -38,7 +35,6 @@ public class ServicioUsuarios {
this.admin.setNombreUsuario("admin");
}
/**
* Función para crear un Socio en la estructura
* @param usuario usuario que se va a añadir
......@@ -55,36 +51,23 @@ public class ServicioUsuarios {
* @return DTOLoginRespuesta con el token si es válido, o null si falla
*/
public DTOLoginRespuesta autenticarUsuario(String email, String contrasenia) {
System.out.println("🔍 Intentando autenticar usuario: " + email);
Optional<Usuario> usuario = repositorioUsuario.findByEmail(email);
if (usuario.isEmpty()) {
System.out.println("❌ Usuario no encontrado: " + email);
return null;
}
System.out.println("✅ Usuario encontrado: " + usuario.get().getEmail());
System.out.println("Contraseña almacenada (encriptada): " + usuario.get().getContrasenia());
System.out.println("Contraseña ingresada: " + contrasenia);
System.out.println("¿Coincide? " + passwordEncoder.matches(contrasenia, usuario.get().getContrasenia()));
if (!passwordEncoder.matches(contrasenia, usuario.get().getContrasenia())) {
System.out.println("❌ Contraseña incorrecta para: " + email);
return null;
}
String rol = "USUARIO_REGISTRADO";
if (email.equals(admin.getEmail())) {
if (!passwordEncoder.matches(contrasenia, passwordEncoder.encode("adminpassword"))) {
System.out.println("❌ Contraseña incorrecta para admin");
return null;
}
rol = "ADMIN";
}
// Datos adicionales en el token (claims)
Map<String, Object> claims = new HashMap<>();
claims.put("email", usuario.get().getEmail());
......@@ -93,9 +76,6 @@ public class ServicioUsuarios {
// Generamos el token JWT
String token = jwtUtil.generateToken(claims, usuario.get().getEmail());
System.out.println("✅ Usuario autenticado exitosamente. Token generado.");
return new DTOLoginRespuesta(token, usuario.get().getEmail(), usuario.get().getContrasenia());
}
......
......@@ -69,7 +69,7 @@ public class TestUsuariosController {
Assertions.assertThat(usuarioCreado.getId()).isNotNull();
// Caso 3: Intentar registrar un usuario con el mismo email
var usuarioDuplicado = new DTOUsuario(null, "carlitos@gmail.com", "Carlitos", "password123");
var usuarioDuplicado = new DTOUsuario(null, "pedro@gmail.com", "Pedro", "pedrito");
var respuestaDuplicado = restTemplateUsuarios.postForEntity(
"/",
usuarioDuplicado,
......
......@@ -7,26 +7,19 @@ import com.ujaen.tfg.mangaffinity.excepciones.UsuarioYaRegistrado;
import com.ujaen.tfg.mangaffinity.rest.DTO.DTOLoginRespuesta;
import com.ujaen.tfg.mangaffinity.seguridad.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import javax.crypto.SecretKey;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@SpringBootTest(classes = {MangAffinityApplication.class, JpaTestConfig.class})
@ActiveProfiles("test")
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class TestServicioUsuarios {
@Autowired
......@@ -48,37 +41,29 @@ public class TestServicioUsuarios {
@Test
@DirtiesContext
void testAutenticarUsuario() {
logger.info("🔍 Iniciando test de autenticación");
// Caso 1: Usuario con email incorrecto
String emailInexistente = "nonexistent@example.com";
String contraseniaValida = "validpassword";
assertThat(servicioUsuarios.autenticarUsuario(emailInexistente, contraseniaValida)).isNull();
logger.info("✅ Caso 1 completado: Usuario inexistente no autenticado");
// Caso 2: Contraseña incorrecta
String emailExistente = "test@example.com";
String contraseniaIncorrecta = "wrongpassword";
assertThat(servicioUsuarios.autenticarUsuario(emailExistente, contraseniaIncorrecta)).isNull();
logger.info("✅ Caso 2 completado: Contraseña incorrecta no autenticada");
// Caso 3: Usuario con email y contraseña correctos
var usuario1 = new Usuario("pedro@gmail.com", "Pedro", "pedrito"); // Se pasa en texto plano
servicioUsuarios.crearUsuario(usuario1);
var usuario2 = new Usuario("pedra@gmail.com", "Pedra", "pedrito"); // Se pasa en texto plano
servicioUsuarios.crearUsuario(usuario2);
Usuario usuarioGuardado = servicioUsuarios.buscaUsuario("pedro@gmail.com");
assertThat(usuarioGuardado).isNotNull();
logger.info("✅ Usuario guardado en BD: {}", usuarioGuardado.getEmail());
logger.info("Contraseña en BD (encriptada): {}", usuarioGuardado.getContrasenia());
DTOLoginRespuesta respuestaValida = servicioUsuarios.autenticarUsuario(usuario1.getEmail(), "pedrito");
DTOLoginRespuesta respuestaValida = servicioUsuarios.autenticarUsuario(usuario2.getEmail(), "pedrito");
assertThat(respuestaValida).isNotNull();
assertThat(respuestaValida.getToken()).isNotNull();
logger.info("✅ Caso 3 completado: Usuario autenticado correctamente");
// Comprobamos que el rol de usuario registrado esté incluido en el token
Claims claims = jwtUtil.decodeJWT(respuestaValida.getToken()); // Usamos la misma clave secreta para decodificar
assertThat(claims.get("rol")).isEqualTo("USUARIO_REGISTRADO");
logger.info("✅ El rol de usuario registrado está presente en el token");
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment