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

[Dúvida] Capturar JWTVerificationException

Estou com a mesma dúvida do tópico https://cursos.alura.com.br/forum/topico-duvida-excecao-para-token-invalido-295035

Em uma das explicação o Otávio explicou que possivelmente ele está sendo tratado antes de chegar ao Handler.

Mas se ele tá dentro de um try catch como é sugerido no curso, ele não sendo tratado?

No caso que esse erro seja tratado com @exceptionHandler eu teria que tirar do try catch? Segue abaixo o código:

getSubject

public String getSubject(String tokenJWT){
        try {
            var algoritmo = Algorithm.HMAC256(secret);
            return JWT.require(algoritmo)
                    .withIssuer("Api Voll.med")
                    .build()
                    .verify(tokenJWT)
                    .getSubject();

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

TratadorDeError

@ExceptionHandler(RuntimeException.class)
    public ResponseEntity tratarError498(JWTVerificationException ex){
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new DadosadosErroValidacao(HttpStatus.UNAUTHORIZED.toString(), "Token Inválido" ));
    }
3 respostas

Corrigindo...


@ExceptionHandler(RuntimeException.class)
    public ResponseEntity tratarError498(RuntimeException ex){
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new DadosadosErroValidacao(HttpStatus.UNAUTHORIZED.toString(), "Token Inválido" ));
    }
solução!

Oi!

Nesse cenário a exception não será tratada pela classe TratadorDeErros, pois ela ocorreu dentro do filter e o Spring que vai capturar.

Você pode tratar de outra forma então:

Crie uma classe Exception para representar esse erro:

public class TokenInvalidoException extends RuntimeException {
    public TokenInvalidoException(String mensagem) {
        super(mensagem);
    }
}

Altere o catch na classe TokenService, no método getSubject()

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

E coloque um try/catch na classe SecurityFilter:

try {
    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);
} catch (TokenInvalidoException e) {
    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write(e.getLocalizedMessage());
}

Dessa forma esse erro em específico será tratado dentro do próprio filter.

Show demais! É isso mesmo.

No caso, baseado na solução acima adicionei mais um catch para diferenciar de um token inválido de um token expirado:

if(tokenJWT != null){
            try{
                var subject = tokenService.getSubject(tokenJWT);
                var usuario = usuarioRepository.findByEmail(subject);

                var authentication = new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities() );
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }catch(TokenInvalidoException ex){
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("Token Inválido");
                return;
            }catch (TokenExpiredException ex){
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("Token Expirado");
                return;

            }