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

403 Forbidden - The input is not a valid base 64 encoded string.

Pessoal poderiam dar um help :

Faço a autenticação no postman http://localhost:8080/login

Consigo o token tranquilamente:

{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhbmEuYmVhdHJpekB2b2xsLm1lZCIsImlzcyI6IkFwaSBWb2xsLm1lZCIsImV4cCI6MTY4NDg2MTQyMn0.lHo0K0llIf41APXO9vZFyHFKamNGqAaAvWkA2HIdRcM" }

Entro no Debugger do JWT.io https://jwt.io/ O Token está com esse status : Invalid Signature

Quanto uso esse mesmo token na API para retornar a lista de médicos usando este token dá erro 403 Forbidden http://localhost:8080/medicos

com.auth0.jwt.exceptions.JWTDecodeException: The input is not a valid base 64 encoded string. at com.auth0.jwt.JWTDecoder.(JWTDecoder.java:46) at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:444) at med.voll.api.infra.security.TokenService.getSubject(TokenService.java:40) at med.voll.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:31) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)

Caused by: java.lang.IllegalArgumentException: Illegal base64 character 20 at java.base/java.util.Base64$Decoder.decode0(Base64.java:848) at java.base/java.util.Base64$Decoder.decode(Base64.java:566) at java.base/java.util.Base64$Decoder.decode(Base64.java:589) at com.auth0.jwt.JWTDecoder.(JWTDecoder.java:41) ... 55 more

va.lang.RuntimeException: **Token JWT inválido ou expirado**
at med.voll.api.infra.security.TokenService.getSubject(TokenService.java:44) ~[classes/:na]
at med.voll.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:31) ~[classes/:na]
@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 Voll.med")
                    .withSubject(usuario.getLogin())
                    .withExpiresAt(dataExpiracao())
                    .sign(algoritmo);
        } catch (JWTCreationException exception){
            throw new RuntimeException("Erro ao gerar token jwt", exception);
        }
    }

    public String getSubject(String tokenJWT){
        try {
            var algoritmo = Algorithm.HMAC256(secret);
             return JWT.require(algoritmo)
                    .withIssuer("API Voll.med")
                    .build()
                     .verify(tokenJWT)
                     .getSubject();
        } catch (JWTVerificationException exception){
            exception.printStackTrace();
            throw new RuntimeException("Token JWT inválido ou expirado");
        }

    }

    private Instant dataExpiracao() {
        return LocalDateTime.now().plusHours(2).toInstant(ZoneOffset.of("-03:00"));
    }
}
6 respostas

Oi Carlos!

O seu issuer está diferente nos métodos gerarToken e getSubject:

.withIssuer("Api Voll.med")
.withIssuer("API Voll.med")

Eles precisam ser iguais!

Alterei na API e validei o token na jwt.io reiniciei mas ainda está com este erro :

com.auth0.jwt.exceptions.JWTDecodeException: The input is not a valid base 64 encoded string.
    at com.auth0.jwt.JWTDecoder.<init>(JWTDecoder.java:46)
    at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:444)
    at med.voll.api.infra.security.TokenService.getSubject(TokenService.java:41)
    at med.voll.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:31)

Caused by: java.lang.IllegalArgumentException: Illegal base64 character 20
    at java.base/java.util.Base64$Decoder.decode0(Base64.java:848)
    at java.base/java.util.Base64$Decoder.decode(Base64.java:566)
    at java.base/java.util.Base64$Decoder.decode(Base64.java:589)
    at com.auth0.jwt.JWTDecoder.<init>(JWTDecoder.java:41)
    ... 55 more
2023-05-23T19:49:14.406-03:00 ERROR 468589 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

java.lang.RuntimeException: Token JWT inválido ou expirado
    at med.voll.api.infra.security.TokenService.getSubject(TokenService.java:45) ~[classes/:na]
    at med.voll.api.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:31) ~[classes/:na]
    public String gerarToken(Usuario usuario) {
        try {
            var algoritmo = Algorithm.HMAC256(secret);
            return JWT.create()
                    .withIssuer("Api Voll.med")
                    .withSubject(usuario.getLogin())
                    .withExpiresAt(dataExpiracao())
                    .sign(algoritmo);
        } catch (JWTCreationException exception){
            throw new RuntimeException("Erro ao gerar token jwt", exception);
        }
    }

    public String getSubject(String tokenJWT){
        try {
            var algoritmo = Algorithm.HMAC256(secret);
             return JWT.require(algoritmo)
                    .withIssuer("Api Voll.med")
                    .build()
                     .verify(tokenJWT)
                     .getSubject();
        } catch (JWTVerificationException exception){
            exception.printStackTrace();
            throw new RuntimeException("Token JWT inválido ou expirado");
        }

    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // recuperar o token
        System.out.println("Chamando o Filter!");
        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); // chama o próximo filtro
        System.out.println("Logado na Requisicao");
    }

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

Coloca um system.out para ver o token que está chegando na API:

if(tokenJWT != null) {
    System.out.println("Token recebido: " +tokenJWT);
//resto do codigo

Chega o Token mas o erro persiste na validade dele estranhoVou subir em modo debug para identificar o que ocorre . obrigado

2023-05-23T20:41:33.634-03:00  INFO 504676 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
Chamando o Filter!
Hibernate: 
    select
        u1_0.id,
        u1_0.login,
        u1_0.senha 
    from
        usuarios u1_0 
    where
        u1_0.login=?
Logado na Requisicao
Chamando o Filter!
Token recebido:  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhbmEuYmVhdHJpekB2b2xsLm1lZCIsImlzcyI6IkFwaSBWb2xsLm1lZCIsImV4cCI6MTY4NDg5MjQ5NH0.J8_wRd1YqgB2RIlBM4ME4z2c6qO1U6OLjb1V31873n8
com.auth0.jwt.exceptions.JWTDecodeException: The input is not a valid base 64 encoded string.
    at com.auth0.jwt.JWTDecoder.<init>(JWTDecoder.java:46)
solução!

Outra coisa que vi, nessa sua linha está faltando o espaço em branco após a palavra Bearer:

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

Deveria ser:

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

Obrigado Rodrigo pela ajuda, Esse espaçinho de nada estava me deixando louco!!! Escrevi todo o projeto junto com a aula para evitar o copy/paste e aprender escrevendo e acompanhando a sua lógica.Agora tudo está funcional .

Valeu mesmo!