Hola buena noche, saben tengo el problema que cuando el subject del token llega al TokenService, si usted llega con el valor de null, y no sé por qué pasa eso estuve investigando acerca del error de qué es lo que genera que obtenga un valor de null : Así que se generó la duda si en este código era que se definía el issuer:
verifier = JWT.require(algorithm)
.withIssuer("Resumes")
.build()
.verify(token);
verifier.getSubject();
Y entre las posibilidades que encontré fueron estos: Firma inválida: Si la firma del token no coincide con la firma esperada según el algoritmo y el secreto proporcionado, se lanzará una excepción y verifier quedará como nulo. Token expirado, Issuer no válido, Token no válido en general,
Así están el código proyecto: Esta es la clase AuthenticationService:
package rsm.ces.api.infra.security;
import org.springframework.beans.factory.annotation.Autowired;
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 rsm.ces.api.domain.usuarios.UsuarioRepository;
@Service
public class AuthenticationService implements UserDetailsService {
@Autowired
private UsuarioRepository usuarioRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return usuarioRepository.findByUser(username);
}
}
Esta es la clase SecurityFilter:
package rsm.ces.api.infra.security;
@Component
public class SecurityFilter extends OncePerRequestFilter {
@Autowired
private TokenService tokenService;
@Autowired
private UsuarioRepository usuarioRepository;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Obtener el token del header
var authHeader = request.getHeader("Authorization");
if (authHeader != null) {
var token = authHeader.replace("Bearer ", "");
var nombreUsuario = tokenService.getSubject(token); // extract username
if (nombreUsuario != null) {
// Token valido
var usuario = usuarioRepository.findByUser(nombreUsuario);
var authentication = new UsernamePasswordAuthenticationToken(usuario, null,
usuario.getAuthorities()); // Forzamos un inicio de sesion
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
Esta es la clase TokenService:
package rsm.ces.api.infra.security;
@Service
public class TokenService {
@Value("${api.security.secret}")
private String apiSecret;
public String generateToken(Usuario usuario){
try {
Algorithm algorithm = Algorithm.HMAC256(apiSecret);
return JWT.create()
.withIssuer("Resumes")
.withSubject(usuario.getUser())
.withClaim("id", usuario.getId())
.withExpiresAt(generateExpirationDate())
.sign(algorithm);
} catch (JWTCreationException exception){
throw new RuntimeException();
}
}
public String getSubject(String token) {
if (token == null) {
throw new RuntimeException();
}
DecodedJWT verifier = null;
try {
Algorithm algorithm = Algorithm.HMAC256(apiSecret); // validando firma
verifier = JWT.require(algorithm)
.withIssuer("Resumes")
.build()
.verify(token);
verifier.getSubject();
} catch (JWTVerificationException exception) {
System.out.println("Error al verificar el token: " + exception.getMessage());
System.out.println(exception.toString());
}
if (verifier.getSubject() == null) {
throw new RuntimeException("Verifier invalido");
}
return verifier.getSubject();
}
private Instant generateExpirationDate(){
return LocalDateTime.now().plusHours(2).toInstant(ZoneOffset.of("-06:00"));
}
}
Ya que lo que he encontrado son maneras para validar de que el subject no sea null, pero el problema es que llega null a la clase TokenService, pero no sé cómo llenarlo con el valor real que no sea nulo. Espero que alguien me pueda ayudar por favor. Les agradezco de antemano.