No mundo das APIs modernas, a segurança é um dos aspectos mais críticos. Garantir que somente usuários autorizados possam acessar recursos protegidos é essencial. E é aqui que o JWT (JSON Web Token) entra em cena. Este método de autenticação é amplamente utilizado devido à sua eficiência, flexibilidade e compatibilidade com diversas linguagens de programação.
Se você já desenvolve APIs em Delphi Horse, sabe o quanto esse framework é ágil e poderoso para criar aplicações web e RESTful. Mas integrar um mecanismo de autenticação robusto como o JWT pode parecer um desafio para quem está começando.
Neste artigo, vamos descomplicar o uso do JWT com o Delphi Horse. Você aprenderá como proteger suas rotas de API, validar tokens e até mesmo adicionar informações personalizadas para enriquecer sua autenticação. Tudo isso de forma prática, com exemplos de código e explicações claras.
Preparado? Vamos direto ao que interessa: segurança simplificada com Delphi Horse e JWT!
O que é JWT e como funciona?
O JWT (JSON Web Token) é uma solução amplamente utilizada para autenticação e troca de informações seguras entre sistemas. Ele é baseado em um padrão aberto (RFC 7519) e utiliza um formato compacto e autocontido para transmitir dados entre partes.
Componentes do JWT
O token JWT é composto por três partes separadas por pontos (.
), formando uma string no seguinte formato:
1 2 3 |
header.payload.signature |
Cada parte desempenha um papel específico:
1. Header
O cabeçalho contém metadados sobre o token, incluindo:
- Algoritmo de assinatura usado para proteger o token, como HMAC SHA256 ou RSA.
- Tipo de token, geralmente definido como
JWT
.
1 2 3 4 5 6 |
{ "alg": "HS256", "typ": "JWT" } |
2. Payload
O payload armazena as informações que queremos transmitir. Ele contém “claims”, que são declarações como:
- Claims registrados: Padrões definidos na especificação, como
sub
(identificação do usuário),exp
(data de expiração), eiat
(data de emissão). - Claims personalizados: Dados adicionais específicos da sua aplicação, como permissões, papéis, etc.
Exemplo de um payload típico:
1 2 3 4 5 6 7 8 |
{ "sub": "1234567890", "name": "John Doe", "admin": true, "iat": 1516239022 } |
3. Signature
A assinatura é a garantia de que o token não foi alterado. Ela é gerada combinando o header e o payload com uma chave secreta e o algoritmo especificado.
A fórmula para criar a assinatura é:
1 2 3 4 5 6 |
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret ) |
A assinatura resultante é anexada ao token e é validada pelo servidor para confirmar sua autenticidade.
Por que usar JWT?
O JWT possui vantagens significativas, especialmente em arquiteturas RESTful:
- Autossuficiência
Como o token contém todas as informações necessárias para autenticação, não é necessário consultar o banco de dados a cada requisição, reduzindo a carga no servidor. - Formato Compacto
O JWT utiliza codificação Base64URL, tornando-o eficiente para transmissão em cabeçalhos HTTP ou URLs. - Flexibilidade
Ele pode ser usado para autenticação de usuários, autorização de acesso (quem pode fazer o quê), e até para troca segura de informações entre serviços. - Compatibilidade
Por ser baseado em um padrão aberto, o JWT pode ser usado em praticamente qualquer linguagem de programação e integrado a diversas plataformas.
Fluxo de Funcionamento do JWT
- Autenticação Inicial
- O cliente (por exemplo, um aplicativo ou navegador) envia as credenciais de login ao servidor (usuário e senha).
- O servidor valida as credenciais e, se corretas, gera um token JWT contendo as informações do usuário e o envia ao cliente.
- Uso do Token
- O cliente armazena o token (geralmente no armazenamento local ou cookies).
- Em cada requisição subsequente, o token é enviado no cabeçalho
Authorization
com o formatoBearer <token>
.
- Validação no Servidor
- O servidor verifica a assinatura do token e valida informações como expiração (
exp
) e emissor (iss
). - Se válido, o acesso ao recurso solicitado é concedido.
- O servidor verifica a assinatura do token e valida informações como expiração (
Quando usar JWT?
O JWT é ideal para cenários onde:
- APIs RESTful precisam ser protegidas sem estado (stateless).
- Existe a necessidade de autenticar usuários em múltiplos serviços ou sistemas.
- Você precisa de uma solução portátil e compatível entre diversas plataformas.
Autenticação com JWT em APIs usando Delphi Horse
No mundo das aplicações RESTful, a segurança é um ponto crítico. Quando lidamos com APIs, é essencial garantir que apenas usuários ou sistemas autorizados acessem os recursos disponíveis. Para isso, o uso de JWT (JSON Web Token) é uma das práticas mais comuns e eficazes.
Neste artigo, vamos criar um exemplo prático com Delphi Horse, implementando duas APIs:
- API de Autenticação: Responsável por gerar o token JWT contendo o CNPJ do cliente como uma claim personalizada.
- API de Negócio (Business): Protegida com JWT, valida os tokens recebidos e permite acesso aos recursos apenas para usuários autenticados.
Você aprenderá como:
- Criar tokens JWT com claims personalizadas.
- Proteger rotas usando middleware para validação de tokens.
- Configurar e conectar duas APIs que trabalham juntas.
1. Criando a API de Autenticação
A API de autenticação será responsável por gerar tokens JWT com informações personalizadas, como o CNPJ. Esse token será usado pela API de negócio para validar o cliente.
Configuração Inicial
Primeiro, configure o projeto instalando as dependências necessárias com o Boss:
Não vou entrar em detalhes sobre a criação de uma API Horse, suponho que já saiba como fazer isso. O que precisará a mais nesse artigo é adicionar a biblioteca JOSE do Paolo Rossi.
1 2 3 |
boss install github.com/paolo-rossi/delphi-jose-jwt |
Em seguida vamos criar uma classe para auxiliar na crição de CLAIMS personalizados. Os claims são como campos que podemos armazenar dentro do token. Existem os claims registrados, obrigatórios do JWT e os claims personalizados. Nesse exemplo vamos simular a adição de um CNPJ dentro do token.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
unit Autenticacao.CustomClaim; interface uses JOSE.Core.JWT, JOSE.Types.JSON; type TCustomClaims = class(TJWTClaims) private function GetCNPJ: string; procedure SetCNPJ(const ACNPJ: string); public property CNPJ: string read GetCNPJ write SetCNPJ; end; implementation uses JOSE.Types.Bytes; function TCustomClaims.GetCNPJ: string; begin Result := TJSONUtils.GetJSONValue('CNPJ', FJSON).AsString; end; procedure TCustomClaims.SetCNPJ(const ACNPJ: string); begin TJSONUtils.SetJSONValueFrom<string>('CNPJ', ACNPJ, FJSON); end; end. |
Essa classe adiciona o campo CNPJ
ao payload do token JWT.
Implementando o Endpoint de Geração do Token
No DPR da nosssa api de autenticação, teremos um endpoint /token para ser chamado e gerar um token de autenticação, veja como fazemos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
program autenticacao; {$APPTYPE CONSOLE} uses Horse, Horse.Jhonson, JOSE.Core.JWT, System.JSON, System.DateUtils, Autenticacao.CustomClaim; begin THorse.Use(Jhonson); THorse.Post('/token', procedure(Req: THorseRequest; Res: THorseResponse) var LToken: TJWT; LCompactToken: string; LCNPJ: string; LClaims: TCustomClaims; LExpiracao: TDateTime; begin Req.Headers.TryGetValue('CNPJ', LCNPJ); if LCNPJ.IsEmpty then begin Res.Send<TJSONObject>(TJSONObject.Create.AddPair('Erro', 'Informe o CNPJ')) .Status(THTTPStatus.BadRequest); Exit; end; LToken := TJWT.Create(TCustomClaims); try LClaims := TCustomClaims(LToken.Claims); LClaims.Issuer := 'Adriano Santos Treinamentos'; LClaims.CNPJ := LCNPJ; LClaims.Expiration := IncMinute(Now, 10); LCompactToken := TJOSE.SHA256CompactToken('adrianosantostreina', LToken); Res.Send<TJSONObject>(TJSONObject.Create .AddPair('Token', LCompactToken) .AddPair('Expiracao', DateToISO8601(LClaims.Expiration))) .Status(THTTPStatus.Created); finally LToken.Free; end; end); THorse.Get('/ping', procedure(Req: THorseRequest; Res: THorseResponse) begin Res.Send<TJSONObject>(TJSONObject.Create.AddPair('Retorno', 'Funcionando')); end); THorse.Listen(9000); end. |
Teste da API de Autenticação
Envie uma requisição para o endpoint /token
com o CNPJ no header um token será retornado. Use o Postman, Inmsonia ou crie um pequeno projeto para fazer a requisição. Um exemplo de token gerado pode ser visto abaixo:
1 2 3 4 5 6 |
{ "Token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJBZHJpYW5vIFNhbnRvcyBUcmVpbmFtZW50b3MiLCJDTlBKIjoiMTQ0MTcyODIwMDAxMzIiLCJleHAiOjE3Mzc5ODEzMjN9.RtMr3HAfF-7C_qL6nWCn3OFuzPt1lmJczN2UyRGCWo0", "Expiracao": "2025-135-27 09:35:23" } |
2. Criando a API de Negócio (Business)
A API de negócio utiliza o middleware HorseJWT
para validar tokens e proteger rotas. Esse middleware pode ser encontrado na seção “Official Middlewares” no github da HashLoad.
Configuração do Middleware JWT
No projeto da API de negócio, implemente a validação de tokens no arquivo principal:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
program business; {$APPTYPE CONSOLE} uses Horse, Horse.Jhonson, Horse.JWT, JOSE.Core.JWT, Autenticacao.CustomClaim; begin THorse.Use(Jhonson); THorse.Use( HorseJWT('adrianosantostreina', THorseJWTConfig.New.SessionClass(TCustomClaims) .SkipRoutes(['/ping', '/version']))); THorse.Get('/ping', procedure(Req: THorseRequest; Res: THorseResponse) begin Res.Send<TJSONObject>(TJSONObject.Create.AddPair('Retorno', 'Funcionando')); end); THorse.Get('/clientes', procedure(Req: THorseRequest; Res: THorseResponse) begin Res.Send<TJSONObject>(TJSONObject.Create.AddPair('Dados', 'Clientes')); end); THorse.Listen(3000); end. |
Teste da API de Negócio
Faça uma requisição para a rota protegida /clientes
enviando o token no cabeçalho. Agora através do Postman, faça uma requisição enviando o token gerado na outra api. Caso esteja ok o token, você receberá o conteúdo como abaixo, simulando o resultado de uma rota.
1 2 3 4 5 |
{ "Dados": "Clientes" } |
As rotas /ping
e /version
não estão sendo protegidas pelo JWT, você pode notar isso na chamada ao skiproutes
.
1 2 3 4 5 6 |
THorse.Use( HorseJWT('adrianosantostreina', THorseJWTConfig.New.SessionClass(TCustomClaims) .SkipRoutes(['/ping', '/version']))); |
Participe da Comunidade no Telegram
🚀 Quer continuar essa discussão e trocar ideias com outros desenvolvedores? Junte-se à nossa comunidade no Telegram! Lá, você pode comentar sobre o que achou deste artigo, tirar suas dúvidas e compartilhar suas experiências com Delphi e ainda discutir ou tirar suas dúvidas sobre os mais variados temas em uma comunidade com mais de 1.000 desenvolvedores.
🔗 Clique aqui para entrar na comunidade
Te vejo lá!
O que virá a seguir?
Criação de logs em APIs com Delphi Horse
No próximo artigo, vamos explorar como implementar logs em APIs desenvolvidas com Delphi Horse. Veremos:
- Configuração de middleware para registrar requisições e respostas.
- Boas práticas para lidar com erros e gerar logs úteis para depuração e análise.
Com essas técnicas, você terá controle total sobre o comportamento de suas APIs, garantindo maior segurança e rastreabilidade.
Conclusão
Neste artigo, criamos duas APIs utilizando o Delphi Horse e implementamos um fluxo completo de autenticação com JWT, incluindo claims personalizadas como o CNPJ. Esse modelo é altamente escalável e pode ser facilmente adaptado para aplicações maiores.
Com essas ferramentas, você tem a base para criar aplicações RESTful seguras e eficientes.
Se desejar expandir o tema, podemos explorar tópicos como:
- Implementação de permissões avançadas.
- Uso de banco de dados para validar credenciais na autenticação.
- Monitoramento de APIs com ferramentas de log.