Solucionado (ver solución)
Solucionado
(ver solución)
1
respuesta

Error de "verifier" is null

Estoy enfrentando el problema que al momento de ejecutar la consulta con el Insomnia me muestra el error de que el verifier es null. Estuve buscando en el foro algunas posibles respuestas, pero ninguna nos funcionó, así que le comparto el código para que también puedan ayudar a solventarlo, gracias. Este es el error que obtengo:

2023-09-23T22:32:50.635-06:00 ERROR 25082 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

java.lang.NullPointerException: Cannot invoke "com.auth0.jwt.interfaces.DecodedJWT.getSubject()" because "verifier" is null
    at med.voll.api.infra.security.TokenService.getSubject(TokenService.java:46) ~[classes/:na]
    at med.voll.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:29) ~[classes/:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.0-M4.jar:6.1.0-M4]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.12.jar:10.1.12]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.12.jar:10.1.12]
    at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) ~[spring-security-web-6.2.0-M2.jar:6.2.0-M2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) ~[spring-security-web-6.2.0-M2.jar:6.2.0-M2]

Esta es la clase TokenService.java

package med.voll.api.infra.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import med.voll.api.domain.usuarios.Usuario;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

@Service
public class TokenService {

    @Value("${api.security.secret}")
    private String apiSecret;
    public String generarToken(Usuario usuario) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(apiSecret);
            return JWT.create()
                    .withIssuer("voll med")
                    .withSubject(usuario.getLogin())
                    .withClaim("id", usuario.getId())
                    .withExpiresAt(generarFechaExpiracion(2))
                    .sign(algorithm);
        } catch (JWTCreationException exception){
            throw new RuntimeException();
        }
    }
    public String getSubject(String token) {
        DecodedJWT verifier  = null;
        try {
            Algorithm algorithm = Algorithm.HMAC256(apiSecret);
            verifier = JWT.require(algorithm)
                    .withIssuer("voll med")
                    .build()
                    .verify(token);
            verifier.getSubject();
        } catch (JWTVerificationException exception) {
            // Invalid signature/claims
        }
        if (verifier.getSubject() == null){
            throw  new RuntimeException("verifier inválido");
        }
        return verifier.getSubject();
    }


    private Instant generarFechaExpiracion(int hours) {
        return LocalDateTime.now().plusHours(hours).toInstant(ZoneOffset.of("-06:00"));
    }

}

Y esta es la clase SecurityFilter.java

package med.voll.api.infra.security;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
public class SecurityFilter extends OncePerRequestFilter {


    @Autowired
    private TokenService tokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println("The filter its being invoked");
        var token = request.getHeader("Authorization");//.replace("Bearer ", "");
        if (token == null || token == ""){
            throw new RuntimeException("El token enviado no es valido");
        }
        token = token.replace("Bearer ", "");
        System.out.println(token);
        System.out.println(tokenService.getSubject(token));
        filterChain.doFilter(request, response);
    }
}

Les agradeceré muchísimo cualquier tipo de ayuda pues ya llevo varios días con este problema: Gracias de antemano por la ayuda.

1 respuesta
solución!

Hola César,

¿Ha podido resolver el problema? Parece que el problema puede estar en la función getSubject(String token) de tu clase TokenService.java. Según el error que obtienes, el objeto verifier sigue siendo null después de intentar verificar el token.

En tu código, si ocurre una excepción JWTVerificationException durante la verificación del token, el objeto verifier no se inicializa y sigue siendo null. Sin embargo, después de este bloque try-catch, intentas acceder al método getSubject() de verifier sin verificar si verifier es null. Esto puede causar la NullPointerException que estás viendo.

Una posible solución para el problema, podrías mover la línea verifier.getSubject(); dentro del bloque try y devolver el resultado directamente desde allí. De esta manera, si la verificación del token falla y se lanza una excepción, no intentarás acceder a verifier.getSubject().

public String getSubject(String token) {
    DecodedJWT verifier  = null;
    try {
        Algorithm algorithm = Algorithm.HMAC256(apiSecret);
        verifier = JWT.require(algorithm)
                .withIssuer("voll med")
                .build()
                .verify(token);
        return verifier.getSubject();
    } catch (JWTVerificationException exception) {
        // Invalid signature/claims
    }
    throw  new RuntimeException("verifier inválido");
}

Este código devolverá el sujeto del token si la verificación se realiza con éxito, y lanzará una excepción si la verificación falla. De esta manera, no intentarás acceder a verifier.getSubject() si verifier es null.

Espero que esto te ayude. Mucho éxito en todo lo que te propongas y si tienes alguna duda aquí estaremos para apoyarte.

¡Vamos juntos!

Si este post te ayudó, por favor, marca como solucionado ✓. Continúa con tus estudios