Aprenda a implementar autenticação JWT
1. Introdução
Autenticação em sistemas modernos não é mais sessão em memória.
Hoje o padrão é:
stateless
escalável
seguro
JWT resolve isso, mas mal implementado vira problema sério.
Aqui vamos montar uma implementação pronta para produção.
2. Arquitetura recomendada
Separação de responsabilidades:
Client → Auth Service → JWT → API Gateway → MicroservicesResponsabilidades:
Auth Service: autentica e gera token
Gateway: valida entrada
Microservices: confiam no token
Nunca misture autenticação com regra de negócio.
3. Estrutura do token JWT
Exemplo de payload:
{
"sub": "user@email.com",
"userId": 1,
"roles": ["ROLE_USER"],
"tenantId": "company_01",
"iat": 1710000000,
"exp": 1710003600
}Boas práticas:
não incluir dados sensíveis
manter payload leve
sempre definir expiração
4. Dependências
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>5. Serviço de geração de token
@Service
public class JwtService {
private final SecretKey key =
Keys.hmacShaKeyFor(Base64.getDecoder().decode("SUA_CHAVE_FORTE_BASE64"));
public String generateToken(User user) {
return Jwts.builder()
.subject(user.getEmail())
.claim("userId", user.getId())
.claim("roles", user.getRoles())
.claim("tenantId", user.getTenantId())
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + 900000))
.signWith(key)
.compact();
}
public Claims extract(String token) {
return Jwts.parser()
.verifyWith(key)
.build()
.parseSignedClaims(token)
.getPayload();
}
}Pontos importantes:
chave com pelo menos 256 bits
expiração curta (15 minutos recomendado)
6. Endpoint de autenticação
@RestController
@RequestMapping("/auth")
public class AuthController {
private final JwtService jwtService;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
User user = authenticate(request);
String token = jwtService.generateToken(user);
return ResponseEntity.ok(Map.of(
"accessToken", token
));
}
}7. Implementação de refresh token
Motivo:
não manter sessão longa no JWT
Tabela:
CREATE TABLE refresh_token (
id BIGINT PRIMARY KEY,
token VARCHAR(255),
user_id BIGINT,
expiry_date TIMESTAMP,
revoked BOOLEAN
);Serviço:
public String refresh(String refreshToken) {
RefreshToken token = findValid(refreshToken);
return jwtService.generateToken(token.getUser());
}8. Segurança com Spring Security
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
)
.build();
}9. Filtro JWT
@Component
public class JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
Claims claims = jwtService.extract(token);
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(
claims.getSubject(),
null,
List.of()
);
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(request, response);
}
}10. Uso em microserviços
Com Resource Server:
spring:
security:
oauth2:
resourceserver:
jwt:
secret-key: SUA_CHAVE_BASE6411. Boas práticas
usar HTTPS sempre
separar Auth Service
usar refresh token
não confiar no frontend
validar token em gateway
12. Erros comuns
usar chave fraca
token sem expiração
validar manualmente em todos serviços
não usar refresh token
Conclusão
JWT não é apenas gerar token.
É arquitetura de segurança.
Quando implementado corretamente:
escala
simplifica autenticação
melhora performance
