Solucionado (ver solução)
Solucionado
(ver solução)
16
respostas

Token não enviado

Estou tendo o erro abaixo ao tentar realizar a requisição do login:

2024-01-12T07:49:26.937-03:00 ERROR 13280 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

java.lang.RuntimeException: Token JWT não enviado no cabeçalho authorization!

16 respostas

Oi!

Manda aqui o código da sua classe SecurityFilter.

Buenas!

Segue:

package com.github.paulopcrp.healthcare.api.infra.security;

import com.github.paulopcrp.healthcare.api.domain.usuario.UsuarioRepository; 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.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; 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;

@Autowired
private UsuarioRepository repository;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response
        , FilterChain filterChain) throws ServletException, IOException {
    var tokenJWT = recuperarToken(request);

    if (tokenJWT != null) {
        var subject = tokenService.getSubject(tokenJWT);
        var usuario = repository.findByLogin(subject);

        var authentication = new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    filterChain.doFilter(request, response);

}

private String recuperarToken(HttpServletRequest request) {
    var authorizationHeader = request.getHeader("Authorization");
    if(authorizationHeader != null) {
        throw new RuntimeException("Token JWT não enviado no cabeçalho authorization!");
    }

    return authorizationHeader.replace("Bearer ", "").trim();
}

}

O problema está nesse if:

if(authorizationHeader != null) {
    throw new RuntimeException("Token JWT não enviado no cabeçalho authorization!");
}

Desse jeito você está obrigando toda requisição a enviar o token, mas tem requisições em que o token não será enviado. Por exemplo, a requisição de efetuar login, pois ela será chamada para se obter um novo token.

Realizei a alteração para:

private String recuperarToken(HttpServletRequest request) {
    var authorizationHeader = request.getHeader("Authorization");
    if(authorizationHeader == null) {
        throw new RuntimeException("Token JWT não enviado no cabeçalho authorization!");
    }

    return authorizationHeader.replace("Bearer ", "").trim();
}

Porem agora esta retornando

java.lang.RuntimeException: Token JWT inválido ou expirado! at com.github.paulopcrp.healthcare.api.infra.security.TokenService.getSubject(TokenService.java:47) ~[classes/:na] at com.github.paulopcrp.healthcare.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:31) ~[classes/:na]

Na verdade tem que ficar assim:

private String recuperarToken(HttpServletRequest request) {
    var authorizationHeader = request.getHeader("Authorization");
    
    if(authorizationHeader != null) {
        return authorizationHeader.replace("Bearer ", "").trim();
    }

    //token não enviado na requisição:
    return null;
}

Realizei a alteração, mas ainda persiste o erro abaixo:

java.lang.RuntimeException: Token JWT inválido ou expirado! at com.github.paulopcrp.healthcare.api.infra.security.TokenService.getSubject(TokenService.java:47) ~[classes/:na] at com.github.paulopcrp.healthcare.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:31) ~[classes/:na]

Agora é problema no token enviado ou algum erro na classe TokenService. Manda o código dela aqui.

Segue:

package com.github.paulopcrp.healthcare.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.github.paulopcrp.healthcare.api.domain.usuario.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.token.secret}")
private String secret;

public String gerarToken(Usuario usuario) {

    try {
        var algoritmo = Algorithm.HMAC256(secret);
        return JWT.create()
                .withIssuer("API HealthCare")
                .withSubject(usuario.getLogin())
                .withExpiresAt(dataExpeiracao())
                .sign(algoritmo);
    } catch (JWTCreationException exception){
        throw new RuntimeException("Erro ao gerar token jwt", exception);
    }
}

public String getSubject(String tokenJWT) {
    System.out.println("Recebeu token: " + tokenJWT);

    try {
        var algoritmo = Algorithm.HMAC256(secret);
        return JWT.require(algoritmo)
                .withIssuer("API HealthCare")
                .build()
                .verify(tokenJWT)
                .getSubject();

    } catch (JWTVerificationException exception){
        throw new RuntimeException("Token JWT inválido ou expirado!");
    }

}


private Instant dataExpeiracao() {

    return LocalDateTime.now().plusHours(2).toInstant(ZoneOffset.of("-03:00:00"));
}

}

A principio está certo o código. Vi que no seu método getSubject() você colocou um system.out para imprimir o token recebido. Manda aqui um print do console com esse token que esta chegando.

Segue:

2024-01-12T09:52:10.016-03:00 INFO 23420 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms Recebeu token: undefined 2024-01-12T09:52:10.067-03:00 ERROR 23420 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

Está vindo um token inválido mesmo:

token: undefined 

Aí precisa ver como você está enviando esse token para a API, pois deve ter algum problema.

Pois é....

Não estou conseguindo fazer esse passo.

Você está enviando a requisição no Insomnia ou Postman? Manda aqui um print da requisição sendo disparada

Pelo Insomnia

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

solução!

Veja na aba Bearer. Nessa requisição de login você não deve enviar token e deve ficar assim:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Putz! Tava comendo bola!!

Valeu!!!

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software