Veja nesta publicação como gerar tokens JWT através do Magic xpi, para adicionar segurança aos serviços REST publicados.
JWT é texto, popularmente chamado de token, adotado oficialmente por muitas APIs REST hoje em dia como “credencial de acesso” daquele cliente (consumidor) que está tentando acessar o serviço.
O objetivo é tanto “identificar” o cliente, quanto determinar o “escopo” dele (nível de acesso ou visibilidade àquele serviço ou dados providos por aquele serviço).
O JWT é dividido em três partes (cfe. imagem abaixo) separadas por um “.“:
- Cabeçalho (vermelho – JSon em Base64), que basicamente define qual criptografia está sendo usada nesse token
- Payload (rosa – JSon em Base64), que são os dados do token. Ali estarão todas as informações pertinentes (cliente, emissor, validade, escopo, etc…) que o provedor julgar necessário
- Signature (azul – Bytes em Base64), que é a assinatura digital, geralmente aplicado o algoritmo HMAC256, HMAC384 ou HAMAC512.
O propósito é que o consumidor da API sempre envie este token no cabeçalho “Authorization” das requisições, ex:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJDbGllbnQxQG1hZ2ljc29mdHdhcmVici5jb20iLCJuYW1lIjoiVXNlcjpDbGllbnQxIiwianRpIjoiOWJiZWMzOTgtMjVkMy00ODc3LWIyMjYtOWE1ODY0MzhlMWQ2IiwiaWF0IjoiMTY4MTY3ODQ3NyIsIm5iZiI6MTY4MTY3ODQ3NywiZXhwIjoxNjgxNjgyMDc3LCJpc3MiOiJNYWdpY3hwaSBieSBNYWdpY1NvZnR3YXJlQlIiLCJhdWQiOiJVc2VyOkNsaWVudDEvR2VuZXJhbCBQdXJwb3NlIn0.ObXxXRSmTfNQ4wj4u8clvNW04rB6tq3bU8n7tYE9O-g
Assim, o provedor pode determinar se quem está consumindo é alguém devidamente autorizado, e também o que ele pode fazer (ter acesso).
O fluxo genérico do consumidor é:
- Consumir um API que retorna o token JWT
- Fornecer este token nas demais APIs consumidas posteriormente, enquanto ele for válido, no cabeçalho ‘Authorization‘
Assim que o token perder sua validade, o consumidor deve solicitar um novo e seguir adiante.
Nesta publicação, veremos a 1a etapa: como gerar e prover um token JWT através do Magic xpi.
Identificação Segura do Cliente
Primeiramente, é preciso que o cliente (consumidor) do serviço identifique-se devidamente, para então receber este token, que é uma autorização de acesso às demais APIs.
A posse deste tipo de token significa por definição, passe livre às APIs (segundo limites impostos pelo conteúdo do token)
O provedor é livre para definir este fluxo de solicitação, mas o exemplo que vamos usar neste post e amplamente adotado hoje em dia, funcionará assim:
- O cliente, por ocasião de seu cadastro na plataforma do provedor do serviço, receberá duas informações exclusivas e imutáveis que são:
- Client Application Key, que é pública e pode trafegar nas requisições HTTP aos serviços
- Client Application Secret Key, que é privada, deve ser bem guardada pelo cliente e nunca trafegar nas requisições HTTP aos serviços
- Quando o cliente consumir a API que gera (ou nega) o token JWT, ele vai prover três informações:
- Seu “Client Application Key“, que é a informação pública e serve como sua identificação de ‘usuário’
- Uma informação aleatória (a seu livre critério), que pode (e deve) mudar a todo instante (não se repetindo em cada chamada à API)
- Assinatura digital dessa informação aleatória, usando a sua “Client Application Secret Key” recebida anteriormente, segundo o algoritmo definido pelo provedor da API
Como por exemplo (valores fictícios):
Client Application Key = Client1
Informação Aleatória = Ramdom1
Assinatura = 9c6c1ae2964ef8704da6598d5c41602f78186321fd041ddb859283506ed03465
De onde veio este valor de assinatura?🤔
Supondo que a informação privada (Client Application Secret Key) deste cliente (Client1) seja:
FB3F5A5F1E7A448BA7215b39d3477d19b39b6f7df4104097
a assinatura HAMAC256 produzida em cima do texto “Ramdom1“, resulta em:
9c6c1ae2964ef8704da6598d5c41602f78186321fd041ddb859283506ed03465
A forma como o cliente vai enviar estas três informações também é de definição livre pelo provedor da API.
Pode ser como conteúdo de um POST Body, pode ser como Query String, ou outras formas.
Neste exemplo, e seguindo alguns padrões de APIs existentes por aí, usaremos três cabeçalhos HTTP para isso:
Authorization: Bearer Client1 X-Authorization-Raw-Data: Ramdom1 X-Authorization-Encrypted-Data: 9c6c1ae2964ef8704da6598d5c41602f78186321fd041ddb859283506ed03465
Quando o provedor receber estas três informações (na sua API), ele vai usar o valor “Client1” e pesquisar em sua base de dados se este cliente/usuário existe.
Encontrando, ele carrega (recupera) o seu “Client Application Secret Key“. Com ele (CASK), aplica a assinatura digital em cima do valor “Ramdom1” e compara se o resultado deu o mesmo que o cliente enviou. Se conferir (são iguais), e não for encontrada nenhuma outra restrição de negócio para este cliente, o token JWT pode gerado e devolvido a ele para uso no acesso às demais APIs.
Se não for, nega o token. Geralmente com um retorno HTTP 401.
Esse fluxo de autorização é mais seguro que o tradicional ‘usuário+senha’, pois a senha ou o equivalente a senha (CASK) não trafega nas requisições.
Implementado este Fluxo no Magic xpi
Primeiramente, vamos habilitar nos arquivos:
- Runtime\mgreq.ini
- Runtime\scripts\config\mgreq.ini
as variáveis HTTP “ALL_RAW” e “HTTP_AUTHORIZATION“:
Criamos então um serviço HTTP no projeto Magic xpi para prover tokens JWT :
Em seguida, criamos um Fluxo de Integração com uma trigger HTTP associada a este serviço HTTP.
Neste fluxo vamos capturar todos os cabeçalhos HTTP disponíveis na requisição que chegou:
E extrair o conteúdo daqueles três que nos interessam: “Authorization“, “X-Authorization-Raw-Data” e “X-Authorization-Encrypted-Data“:
O próximo passo, é validar estas informações cfe. explicado anteriormente (mais acima). Não há necessidade de detalhar uma regra de negócio neste post, mas lembre-se que ela implica em usar estas três informações que o cliente (consumidor) passou para se identificar.
Se a validação for “OK“, segue adiante para a geração do token. Senão, nega a geração do token:
Exemplo de resposta negativa:
Mas como gerar este token JWT no Magic xpi? 🤔
Existe uma especificação técnica para o JWT, mas nós não iremos implementá-la.
Pois existem diversos componentes prontos tanto em Java quanto em .NET FW que produzem estes tokens, então vamos usar a capacidade que o Magic xpi tem de integrar-se nativamente a estas tecnologias/plataformas e reaproveitar o que já foi feito antes, sem reinventar.
Neste exemplo, por preferência do autor, vamos integrar com o .NET FW (como demonstrado anteriormente aqui):
Uma vez que tenhamos clicado em “Generate” e depois em “Edit“, temos o esqueleto de uma classe .NET à nossa disposição (aqui está sendo usado o MS Visual Studio):
Primeiramente, precisamos alterar o target nas propriedades do projeto de “.NET 4” para “.NET 4.6.2” (ou maior):
Em seguida, temos de acessar o NuGet Package Manager e instalar o pacote (gratuito) System.IdentityModel.Tokens.Jwt:
O componente será então atualizado com uma série de novas referências:
Por fim, basta adicionar a regra de negócio no método “Invoke” da classe, que vai pegar dados do fluxo de integração, gerar o token, e devolver o resultado ao fluxo de integração:
Nota*: Ao invés de .NET, você poderia usar componentes Java através do Java Class Connector
Com o valor (token) devidamente gerado, retornamos este conteúdo como resposta à requisição feita à API:
E pronto! Agora temos uma API REST Magic xpi que gera tokens JWT :
Baixe deste endereço o projeto exemplo Magic xpi 4.13 que foi usado neste post, e veja como é fácil implantar a segurança do JWT em suas APIs REST.
Fique ligado no Blog MagicBR, para mais dicas.
Para receber os artigos do Blog Magic Brasil em primeira mão no seu email, registre-se aqui