Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 20 additions & 43 deletions src/main/java/pe/edu/utp/controller/ArticuloController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@

import java.util.List;

import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -18,27 +15,23 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import pe.edu.utp.exception.NoDataFoundException;
import pe.edu.utp.converter.ArticuloConverter;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import pe.edu.utp.dto.ArticuloDto;
import pe.edu.utp.entity.Articulo;
import pe.edu.utp.exception.NoDataFoundException;
import pe.edu.utp.service.ArticuloService;

@RestController
@RequestMapping("/articulos")
@Validated
@RequiredArgsConstructor
@Slf4j
public class ArticuloController {

private final ArticuloService articuloService;

private final ArticuloConverter articuloConverter;

@Autowired
public ArticuloController(ArticuloService articuloService, ArticuloConverter articuloConverter) {
this.articuloService = articuloService;
this.articuloConverter = articuloConverter;
}

@GetMapping
public ResponseEntity<List<ArticuloDto>> getAll(

Expand All @@ -50,49 +43,33 @@ public ResponseEntity<List<ArticuloDto>> getAll(
@RequestParam(value = "limit", required = false, defaultValue = "5") int pageSize) {

Pageable pageable = PageRequest.of(pageNumber, pageSize);
List<Articulo> articulos;
List<ArticuloDto> articulos;
if (marca == null || categoria == null || precioMin == null || precioMax == null) {
articulos = articuloService.findAll(pageable);
} else {
articulos = articuloService.findByCategoriaAndMarcaAndPrecio(categoria,marca,precioMin,precioMax, pageable);

}

if (articulos.isEmpty()) {
return ResponseEntity.noContent().build();
articulos = articuloService.findByCategoriaAndMarcaAndPrecio(categoria, marca, precioMin, precioMax, pageable);
}
List<ArticuloDto> articulosDTO = articuloConverter.fromEntity(articulos);
return ResponseEntity.ok(articulosDTO);
return ResponseEntity.ok(articulos);
}

@GetMapping(value = "/{id}")
public ResponseEntity<ArticuloDto> findById(@PathVariable("id") int id)
throws NoDataFoundException {
Articulo articulo = articuloService.findById(id);
if (articulo == null) {
return ResponseEntity.notFound().build();
}
ArticuloDto articuloDTO = articuloConverter.fromEntity(articulo);
return ResponseEntity.ok(articuloDTO);
public ResponseEntity<ArticuloDto> findById(@PathVariable("id") int id) {
log.info("Obteniendo articulo con ID: {}", id);
var response = articuloService.findById(id);
return ResponseEntity.ok(response);
}

@PostMapping
public ResponseEntity<ArticuloDto> create(@Valid @RequestBody ArticuloDto articulo) {
Articulo registro = articuloService.save(articuloConverter.fromDto(articulo));
ArticuloDto registroDTO = articuloConverter.fromEntity(registro);
return ResponseEntity.status(HttpStatus.CREATED).body(registroDTO);
public ResponseEntity<Articulo> create(@Valid @RequestBody ArticuloDto articuloDto) {
Articulo registro = articuloService.save(articuloDto);
return ResponseEntity.status(HttpStatus.CREATED).body(registro);
}

@PutMapping(value = "/{id}")
public ResponseEntity<ArticuloDto> update(
public ResponseEntity<Articulo> update(
@PathVariable("id") int id, @Valid @RequestBody ArticuloDto articuloDto) {
Articulo articuloUpdate = articuloService.update(articuloConverter.fromDto(articuloDto));

if (articuloUpdate == null) {
return ResponseEntity.notFound().build();
}
ArticuloDto articuloUpdateDTO = articuloConverter.fromEntity(articuloUpdate);
return ResponseEntity.ok(articuloUpdateDTO);
Articulo articuloUpdate = articuloService.update(articuloDto, id);
return ResponseEntity.ok(articuloUpdate);
}

@DeleteMapping(value = "/{id}")
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/pe/edu/utp/controller/UsuarioController.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
package pe.edu.utp.controller;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.catalina.User;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;
import pe.edu.utp.converter.UsuarioConverter;
import pe.edu.utp.dto.LoginRequestDto;
import pe.edu.utp.dto.LoginResponseDto;
Expand Down
1 change: 0 additions & 1 deletion src/main/java/pe/edu/utp/dto/LoginResponseDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@
public class LoginResponseDto {
private UsuarioResponseDto usuario;
private String token;
private String refreshToken;
}
48 changes: 0 additions & 48 deletions src/main/java/pe/edu/utp/security/ApplicationConfig.java

This file was deleted.

30 changes: 30 additions & 0 deletions src/main/java/pe/edu/utp/security/CustomerUserDetailsService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package pe.edu.utp.security;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import pe.edu.utp.entity.Usuario;
import pe.edu.utp.repository.UsuarioRepository;

@Service
@RequiredArgsConstructor
public class CustomerUserDetailsService implements UserDetailsService {

private final UsuarioRepository usuarioRepository;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
Usuario usuario = usuarioRepository.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));

return org.springframework.security.core.userdetails.User.builder()
.username(usuario.getEmail())
.password(usuario.getPassword())
.roles(usuario.getRol().name()).build();
}

}
116 changes: 81 additions & 35 deletions src/main/java/pe/edu/utp/security/JwtAuthenticationFilter.java
Original file line number Diff line number Diff line change
@@ -1,56 +1,102 @@
package pe.edu.utp.security;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Component
@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
private final CustomerUserDetailsService customerUserDetailsService;
private final ObjectMapper objectMapper;

@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
log.info("authHeader valor es: " + authHeader);
final String jwt;
final String userEmail;
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
log.info("No Authorization header or invalid format");
filterChain.doFilter(request, response);
return;
}
jwt = authHeader.substring(7);
userEmail = jwtService.extractUsername(jwt);
log.info("User Email: {}", userEmail);
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
log.info("User Details: {}", userDetails);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
} else{
log.info("Invalid token");
}
}
filterChain.doFilter(request, response);


try{
String jwt = jwtService.extractToken(request);
if(jwt == null ){
log.info("JWT token is missing for request: {}", request.getRequestURI());
filterChain.doFilter(request, response); // Pasa la solicitud si no hay JWT
return; // Importante: retornar después de pasar
}

// Opcional: Si el usuario ya está autenticado, no procesar el JWT de nuevo
if (SecurityContextHolder.getContext().getAuthentication() != null &&
SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
log.debug("User already authenticated in SecurityContext. Skipping JWT processing for {}.", request.getRequestURI());
filterChain.doFilter(request, response); // Pasa la solicitud si ya está autenticado
return;
}

Claims claims = jwtService.resolveClaims(request); // Esto puede lanzar ExpiredJwtException, etc.

if(claims != null && jwtService.validateClaims(claims)){
String username = jwtService.extractUsername(jwt);
UserDetails userDetails = customerUserDetailsService.loadUserByUsername(username);

Authentication authentication =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
log.debug("User '{}' authenticated via JWT with roles: {}. Proceeding with filter chain.", username, userDetails.getAuthorities());
} else {
// Si el token no es válido (ej. claims null o no validan), pero no lanzó una excepción,
// loguear y opcionalmente denegar o simplemente pasar sin autenticar.
log.warn("Invalid JWT token or claims for {}. Not authenticating.", request.getRequestURI());
// Podrías poner un error 401/403 aquí si un token _debe_ ser válido para cualquier ruta no permitAll
// response.setStatus(HttpStatus.UNAUTHORIZED.value());
// response.setContentType(MediaType.APPLICATION_JSON_VALUE);
// objectMapper.writeValue(response.getWriter(), Map.of("error", "Invalid JWT Token"));
// return;
}

// ¡ESTA ES LA LÍNEA CLAVE PARA LAS SOLICITUDES CON TOKEN VÁLIDO!
filterChain.doFilter(request, response);

} catch (ExpiredJwtException ex) {
log.error("JWT token expired for request {}: {}", request.getRequestURI(), ex.getMessage());
Map<String, Object> errorDetails = new HashMap<>();
errorDetails.put("error", "JWT Token expired");
response.setStatus(HttpStatus.UNAUTHORIZED.value()); // Un 401 es más apropiado para token expirado
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
objectMapper.writeValue(response.getWriter(), errorDetails);

} catch (Exception e) { // Captura cualquier otra excepción relacionada con el JWT (firma inválida, etc.)
log.error("Error processing JWT token for request {}: {}", request.getRequestURI(), e.getMessage());
Map<String, Object> errorDetails = new HashMap<>();
errorDetails.put("error", "Invalid JWT token");
response.setStatus(HttpStatus.FORBIDDEN.value()); // O 401 Unauthorized
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
objectMapper.writeValue(response.getWriter(), errorDetails);

}

}
}
Loading