Autenticação Segura com Spring Boot e JWT Usando a Biblioteca jjwt

O JWT (JSON Web Token) é um padrão aberto para tranmsissão segura de informações entre partes como um objeto JSON. Pode ser implementado em diversas linguagens, incluindo Java, com bibliotecas como jjwt, jose4j e nimbus-jose-jwt. Neste exemplo, utilizraemos o jjwt para integrar JWT com Spring Boot.

  1. Adicionando a Dependência no Projeto Spring Boot

Inclua a biblioteca jjwt no seu arquivo de build, por exemplo, no Maven:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.11.5</version>
</dependency>
  1. Criando a Classe Utilitária para JWT

Implemente uma classe para geração e validação de tokens. Esta classe deve ser gerenciada pelo Spring.

import java.util.Date;
import java.util.Map;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class UtilidadeTokenJwt {

    @Value("${jwt.emissor}")
    private String emissor;

    @Value("${jwt.audiencia}")
    private String audiencia;

    @Value("${jwt.tempo_expiracao}")
    private int tempoExpiracao;

    @Value("${jwt.cabecalho}")
    private String cabecalhoAutorizacao;

    private final String chaveAssinatura = "minha-aplicacao-secreta";
    private final SignatureAlgorithm algoritmo = SignatureAlgorithm.HS256;

    public String gerarToken(Map<String, Object> dadosExtras) {
        if (dadosExtras != null) {
            dadosExtras.replaceAll((k, v) -> v.toString());
        }

        return Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuer(emissor)
                .setSubject("sistema")
                .setAudience(audiencia)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + tempoExpiracao * 60000))
                .addClaims(dadosExtras)
                .signWith(algoritmo, chaveAssinatura)
                .compact();
    }

    public boolean verificarExpiracao(String token) {
        Claims reivindicacoes = extrairReivindicacoes(token);
        if (reivindicacoes == null || reivindicacoes.getExpiration() == null) {
            return true;
        }
        return reivindicacoes.getExpiration().before(new Date());
    }

    public String obterAssunto(String token) {
        Claims reivindicacoes = extrairReivindicacoes(token);
        return reivindicacoes != null ? reivindicacoes.getSubject() : null;
    }

    public String obterDadoEspecifico(String token, String chave) {
        Claims reivindicacoes = extrairReivindicacoes(token);
        return reivindicacoes != null ? (String) reivindicacoes.get(chave) : null;
    }

    private Claims extrairReivindicacoes(String token) {
        return Jwts.parser()
                .setSigningKey(chaveAssinatura)
                .parseClaimsJws(token)
                .getBody();
    }
}
  1. Implementando o Interceptor de Autenticação

Crie um interceptor para verificar o token em cada requisição, exceto em endpoints específicos.

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class InterceptadorToken extends HandlerInterceptorAdapter {

    private final UtilidadeTokenJwt utilidadeToken;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public InterceptadorToken(UtilidadeTokenJwt utilidadeToken) {
        this.utilidadeToken = utilidadeToken;
    }

    @Override
    public boolean preHandle(HttpServletRequest requisicao, HttpServletResponse resposta, Object handler) {
        String token = requisicao.getHeader("token");
        if (token == null) {
            logger.warn("Token ausente na requisição");
            resposta.setStatus(HttpServletResponse.SC_FORBIDDEN);
            return false;
        }

        if (utilidadeToken.verificarExpiracao(token)) {
            logger.warn("Token expirado");
            resposta.setStatus(HttpServletResponse.SC_FORBIDDEN);
            return false;
        }

        String assunto = utilidadeToken.obterAssunto(token);
        if (!"sistema".equals(assunto)) {
            logger.warn("Assunto do token inválido");
            resposta.setStatus(HttpServletResponse.SC_FORBIDDEN);
            return false;
        }

        return true;
    }
}
  1. Configurando o Interceptor no Spring Boot

Registre o interceptor na configuração MVC para aplicar a autenticação globalmente.

import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ConfiguracaoWebMVC implements WebMvcConfigurer {

    @Autowired
    private UtilidadeTokenJwt utilidadeToken;

    @Override
    public void addInterceptors(InterceptorRegistry registro) {
        registro.addInterceptor(new InterceptadorToken(utilidadeToken))
                .addPathPatterns("/**")
                .excludePathPatterns(Arrays.asList("/api/gerar-token"));
    }
}
  1. Fluxo de Uso Básico

Para obter um token, uma requisição pode ser feita a um endpoint como /api/gerar-token, que deve retornar um token válido. Em requisições subsequentes, inclua o token no cabeçalho token para acessar recursos protegidos.

Tags: Spring Boot jwt jjwt java autenticacao

Publicado em 6-2 06:14 por Thomas