← Voltar para Documentação
🔐 Sistema de Autorização JWT - Implementação UNAUTHORIZED
📋 Visão Geral do Sistema
Este documento descreve como implementar um sistema robusto de autorização JWT com tratamento adequado de erros UNAUTHORIZED para projetos Spring Boot.
🎯 Objetivos:
- 401 UNAUTHORIZED: Cliente não forneceu credenciais
- 403 FORBIDDEN: Cliente autenticado mas sem permissão
- 500 INTERNAL_SERVER_ERROR: Erro interno da aplicação
🛠️ Componentes do Sistema
1. AuthService - Validação de Tokens
package com.lad.bi.api.util;
import org.springframework.stereotype.Service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
@Service
public class AuthService {
public Claims validarToken(String token, String segredo) {
return Jwts.parser()
.setSigningKey(segredo)
.parseClaimsJws(token)
.getBody();
}
}
2. Método de Validação Central
private Claims validarTokenHeader(String token) {
// 1. Verificar se token foi fornecido
if (token == null || token.trim().isEmpty()) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,
"Token de autorização não fornecido. Use o header Authorization com 'Bearer <token>'.");
}
try {
// 2. Processar formato Bearer
String t = token.trim();
if (t.toLowerCase().startsWith("bearer ")) {
t = t.substring(7).trim();
}
// 3. Verificar se token não está vazio
if (t.isEmpty()) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,
"Token Bearer vazio. Forneça um token válido.");
}
// 4. Validar token JWT
return authService.validarToken(t, jwtSecret);
} catch (ResponseStatusException e) {
throw e; // Re-throw exceções HTTP
} catch (Exception e) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN,
"Token inválido ou expirado. Faça login novamente.");
}
}
}
🎯 Geração de Tokens JWT
Endpoint com idEmpresa Opcional
O sistema possui um endpoint para geração de tokens JWT com suporte a idEmpresa opcional (desde v3.0.4):
/**
* Gera token JWT para autenticação POS
* @param idUsuario ID do usuário (obrigatório)
* @param idEmpresa ID da empresa (OPCIONAL desde v3.0.4)
* @param email Email do usuário (obrigatório)
* @param senha Senha do usuário (obrigatório)
*/
@PostMapping("/pos/token")
public String gerarTokenPos(@RequestParam Long idUsuario,
@RequestParam(required = false) Long idEmpresa, // OPCIONAL
@RequestParam String email,
@RequestParam String senha,
@RequestParam(required = false) Long expiracaoMillis)
🆕 Nova Funcionalidade v3.0.4:
- 🏢 Com idEmpresa: Valida usuário específico da empresa (comportamento anterior)
- 🌐 Sem idEmpresa: Valida apenas email/senha sem restrição de empresa (NOVO)
- ✅ Compatibilidade: Todas as chamadas existentes continuam funcionando
Exemplos de Uso:
# 1. Token específico para empresa (comportamento anterior)
POST /api/pos/token
Content-Type: application/x-www-form-urlencoded
idUsuario=123&idEmpresa=456&email=usuario@teste.com&senha=123456
# 2. Token global sem empresa (NOVA funcionalidade)
POST /api/pos/token
Content-Type: application/x-www-form-urlencoded
idUsuario=123&email=usuario@teste.com&senha=123456
📊 Lógica de Status HTTP
| Status |
Código |
Quando Usar |
Exemplo |
| UNAUTHORIZED |
401 |
Token não fornecido ou formato inválido |
Header Authorization ausente |
| FORBIDDEN |
403 |
Token inválido, expirado ou sem permissão |
JWT malformado, expirado |
| INTERNAL_SERVER_ERROR |
500 |
Erro interno da aplicação |
Falha na validação por erro de código |
🔄 Implementação em Endpoints
@GetMapping("/dados-protegidos")
public String getDadosProtegidos(
@RequestHeader(HttpHeaders.AUTHORIZATION) String token) {
try {
// SEMPRE validar token primeiro
Claims claims = validarTokenHeader(token);
// Processar lógica de negócio
String userId = claims.getSubject();
return "Dados acessados por: " + userId;
} catch (ResponseStatusException e) {
// Re-throw erros de autorização (401/403)
throw e;
} catch (Exception e) {
// Erro interno (500)
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"Erro interno: " + e.getMessage());
}
}
⚙️ Configuração Necessária
1. Dependências Maven (pom.xml)
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2. Configuração (application.properties)
# JWT Configuration
jwt.secret=change-me-replace-with-secure-secret
⚠️ IMPORTANTE - Segurança:
- Use secrets com pelo menos 32 caracteres
- Configure via variáveis de ambiente em produção
- Nunca commite secrets no código
- Use HTTPS em produção
🧪 Testes e Validação
Cenários de Teste com Postman/Insomnia:
# 1. Sem token (401 UNAUTHORIZED)
GET /api/dados-protegidos
# Resultado esperado: 401
# 2. Token vazio (401 UNAUTHORIZED)
GET /api/dados-protegidos
Authorization: Bearer
# Resultado esperado: 401
# 3. Token inválido (403 FORBIDDEN)
GET /api/dados-protegidos
Authorization: Bearer token_invalido
# Resultado esperado: 403
# 4. Token válido (200 OK)
GET /api/dados-protegidos
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
# Resultado esperado: 200
📂 Estrutura do Projeto
src/main/java/com/projeto/api/
├── util/
│ └── AuthService.java # Validação JWT
├── resource/
│ ├── DashboardKdsResource.java # Controller com autorização
│ └── ExemploControllerProtegido.java # Template
└── config/
└── SecurityConfig.java # (Opcional)
src/main/resources/
└── application.properties # Configuração JWT
✅ Checklist de Implementação
- ☐ Adicionar dependência
jjwt no pom.xml
- ☐ Criar/configurar
AuthService
- ☐ Configurar
jwt.secret no application.properties
- ☐ Implementar método
validarTokenHeader()
- ☐ Usar
@RequestHeader(HttpHeaders.AUTHORIZATION)
- ☐ Implementar tratamento 401 vs 403
- ☐ [NOVO] Implementar endpoint
/pos/token com idEmpresa opcional
- ☐ [NOVO] Criar método
validarCredenciaisSemEmpresa()
- ☐ [NOVO] Implementar lógica dupla de validação (com/sem empresa)
- ☐ Adicionar logs de segurança
- ☐ Testar todos os cenários de autorização (incluindo sem idEmpresa)
- ☐ Configurar secrets seguros em produção
🔗 Links Relacionados
📚 Documentação LAD Food
Sistema de Autorização JWT - v3.0.4
Atualizado em: 17 de outubro de 2025
🆕 Novidade: idEmpresa opcional no endpoint /pos/token