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.
- 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>
- 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();
}
}
- 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;
}
}
- 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"));
}
}
- 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.