Proteja seus recursos de API para comunicação máquina a máquina
Aprenda como usar OAuth 2.0 e JWT para proteger seus recursos de API para comunicação máquina a máquina.
Ao construir um projeto que envolve vários serviços, a segurança dos recursos de API é uma preocupação crítica. Neste artigo, mostrarei como usar OAuth 2.0 e JWT para proteger a comunicação entre serviços (máquina a máquina) e como aplicar controle de acesso baseado em funções (RBAC) para seguir o princípio do privilégio mínimo.
Comece
Para acompanhar, assumo que você possui os seguintes pré-requisitos:
- Uma conta do Logto Cloud, ou uma instância auto-hospedada do Logto
- Pelo menos dois serviços que precisam se comunicar entre si
Para fins de demonstração, vamos assumir que temos os seguintes serviços:
- Um serviço de carrinho de compras que fornece APIs para gerenciar carrinhos de compras
- Endpoint:
https://cart.example.com/api
- Endpoint:
- Um serviço de pagamento que fornece APIs para processar pagamentos
- Endpoint:
https://payment.example.com/api
- Endpoint:
Fluxo de autenticação
Agora, nosso serviço de carrinho precisa chamar o serviço de pagamento para processar pagamentos. O fluxo de autenticação é o seguinte:
Alguns conceitos chave no diagrama acima:
- JWT (RFC 7519): JSON Web Token. Veja nosso artigo anterior para uma introdução ao JWT.
- JWK (RFC 7517): JSON Web Key que é usada para verificar a assinatura de um JWT. Um conjunto JWK é um conjunto de JWKs.
- Concessão "client_credentials" (RFC 6749): Um tipo de concessão em OAuth 2.0. Utiliza as credenciais do cliente para obter um token de acesso. Vamos demonstrar os detalhes nas seções seguintes.
Cada participante no diagrama acima tem um papel a desempenhar no fluxo de autenticação:
- Serviço de carrinho: O cliente que precisa chamar o serviço de pagamento. Embora seja um serviço, ainda é um cliente no contexto do OAuth 2.0, e chamamos tais clientes de "aplicativos máquina a máquina" no Logto.
- Logto: O servidor de autorização OAuth 2.0 que emite tokens de acesso.
- Serviço de pagamento: O recurso de API que fornece APIs para processar pagamentos.
Vamos passar pelo fluxo de autenticação passo a passo.
Configuração inicial
Para realizar o fluxo de autenticação, precisamos criar um aplicativo máquina a máquina (serviço de carrinho) e um recurso de API (serviço de pagamento) no Logto.
Criar recurso de API
Como nosso serviço de carrinho precisa estar ciente da API do serviço de pagamento ao realizar a autenticação, precisamos criar primeiro um recurso de API. Vá para o Console do Logto, clique em Recursos de API na barra lateral esquerda e clique em Criar recurso de API. No diálogo aberto, oferecemos alguns tutoriais para ajudá-lo a começar. Você também pode clicar em Continuar sem tutorial para pular.
Digite o nome e o identificador da API, por exemplo, Serviço de pagamento
e https://payment.example.com/api
, depois clique em Criar recurso de API.
Depois de criar o recurso de API, você será redirecionado para a página de detalhes. Podemos deixá-la como está por enquanto.
Criar aplicativo máquina a máquina
Clique em Aplicações na barra lateral esquerda e clique em Criar aplicação. No diálogo aberto, encontre o cartão Máquina a máquina e clique em Começar a construir.
Digite o nome da aplicação, por exemplo, Serviço de carrinho
, e clique em Criar aplicação. Um guia interativo será mostrado para ajudá-lo a configurar a aplicação. Você pode seguir o guia para entender o uso básico, ou clicar em Concluir e finalizar para pular.
Solicitar token de acesso
Desde que as aplicações máquina a máquina são consideradas seguras (por exemplo, elas são implantadas em uma rede privada), podemos usar a concessão "client_credentials" do OAuth 2.0 para obter um token de acesso. Utiliza autenticação básica para autenticar o cliente:
- A URL de solicitação é o endpoint do token da sua instância do Logto. Você pode encontrá-la e copiá-la na guia Configurações avançadas da página de detalhes do aplicativo máquina a máquina.
- O método de solicitação é
POST
. - O cabeçalho
Content-Type
da solicitação éapplication/x-www-form-urlencoded
. - Para o cabeçalho
Authorization
, o valor éBasic <base64(app_id:app_secret)>
, ondeapp_id
eapp_secret
são o ID do aplicativo e o segredo do aplicativo do aplicativo máquina a máquina, respectivamente. Você pode encontrá-los na página de detalhes da aplicação. - O corpo da solicitação precisa especificar o tipo de concessão e o identificador da API. Por exemplo,
grant_type=client_credentials&resource=https://payment.example.com/api
.grant_type=client_credentials
: O valor constante para a concessão "client_credentials".resource=https://payment.example.com/api
: O identificador da API do recurso de API que o cliente deseja acessar.- Se a aplicação precisar ser autorizada com escopos (permissões), você também pode especificar os escopos no corpo da solicitação. Por exemplo,
scope=read:payment write:payment
. Vamos abordar os escopos mais adiante.
Aqui está um exemplo da solicitação usando curl
:
Um corpo de resposta bem-sucedido seria assim:
Enviar solicitação com cabeçalho de autorização
Agora temos o token de acesso e podemos anexá-lo ao cabeçalho Authorization
da solicitação ao recurso de API. Por exemplo, se quisermos chamar a API POST /payments
do serviço de pagamento, podemos enviar a seguinte solicitação:
Validar JWT
Você pode notar que o serviço de pagamento precisa validar o JWT usando o conjunto JWK e pode ter um cache de conjunto JWK local para evitar buscar o conjunto JWK do Logto toda vez. Felizmente, devido à popularidade do JWT, existem muitas bibliotecas que podem ajudá-lo a alcançar o objetivo com algumas linhas de código.
Essas bibliotecas são geralmente chamadas de "jose" (Assinatura e Criptografia de Objetos JSON) ou "jsonwebtoken". Por exemplo, no Node.js podemos usar jose para validar o JWT:
Se a validação for bem-sucedida, a variável payload
será o payload decodificado do JWT. Caso contrário, um erro será lançado.
Aplicar controle de acesso baseado em funções
Agora protegemos com sucesso a comunicação entre o serviço de carrinho e o serviço de pagamento. No entanto, o fluxo de autenticação apenas garante que o cliente seja o verdadeiro serviço de carrinho, mas n ão garante que o serviço de carrinho tenha permissão para realizar ações no serviço de pagamento.
Digamos que queremos permitir que o serviço de carrinho crie pagamentos, mas não leia pagamentos.
Definir permissões
No Logto, "escopos" e "permissões" são intercambiáveis. Acesse a página de detalhes do recurso de API do serviço de pagamento e navegue até a guia Permissões. Ela deve estar vazia agora. Clique em Criar permissão, insira read:payment
como o nome da permissão e Ler pagamentos
como a descrição da permissão. Em seguida, clique em Criar permissão.
Repita os passos acima para criar outra permissão com o nome write:payment
e a descrição Criar pagamentos
.
Criar função máquina a máquina
Uma função é um grupo de permissões. No Logto, aplicativos máquina a máquina podem ser atribuídos a funções para conceder permissões. Clique em "Funções" na barra lateral esquerda e clique em Criar função.
- Digite
checkout
como o nome da função eServiço de checkout
como a descrição da função. - Clique em Mostrar mais opções. Escolha "Função de aplicativo máquina a máquina" como o tipo de função.
- Na seção "Permissões atribuídas", clique no ícone de seta à esquerda do nome do recurso de API (Serviço de pagamento) e selecione a permissão
write:payment
. - Clique em Criar função.
- Como já temos um aplicativo máquina a máquina (Serviço de carrinho), podemos atribuir diretamente a função a ele no próximo passo. Marque a caixa à esquerda do nome do aplicativo (Serviço de carrinho) e clique em Atribuir aplicações.
Solicitar token de acesso com escopos
Além dos parâmetros do corpo da solicitação que mencionamos em Solicitar token de acesso, também podemos especificar os escopos no corpo da solicitação. Por exemplo, se quisermos solicitar a permissão write:payment
, podemos enviar a seguinte solicitação:
Para solicitar múltiplos escopos, você pode separá-los com espaços. Por exemplo, scope=write:payment read:payment
.
Validar escopos
Se uma ação precisar da permissão write:payment
no serviço de pagamento, podemos validar os escopos ao afirmar que o claim scope
do payload do JWT:
Conclusão
Se você quiser proteger o acesso ao serviço de carrinho, também pode aplicar o mesmo fluxo de autenticação. Desta vez, o serviço de carrinho é o recurso de API, e o cliente é outro serviço que precisa acessar.
Com o Logto, seus recursos de API são protegidos com OAuth 2.0 e JWT, e você pode seguir o princípio do privilégio mínimo aplicando controle de acesso baseado em funções. Além disso, você também pode usar o Logto para gerenciar seus usuários e suas permissões, e até integrar com provedores de identidade de terceiros.