SOA / Microsserviços: Como lidar com a autorização nas comunicações entre serviços?

18

Primeiro plano

Estamos passando de uma plataforma monolítica para uma arquitetura mais orientada a serviços. Estamos aplicando princípios DDD muito básicos e dividindo nosso domínio em diferentes contextos limitados. Cada domínio é distribuído e expõe um serviço por meio de uma API da web (REST).

Devido à natureza de nossos negócios, temos serviços como Reservas , Serviços , Clientes , Produtos , etc.

Também configuramos um Identity Server (baseado no Thinktecture Identity Server 3) cuja principal função é:

  • Centralize a autenticação (dadas credenciais que emite tokens)
  • Adicione declarações nos tokens, como: os escopos do cliente (conforme cliente, quero dizer o aplicativo que está fazendo a solicitação), identificador do cliente (conforme cliente, quero dizer a pessoa que usa o aplicativo)

Também introduzimos o papel de um API Gateway que centraliza o acesso externo aos nossos serviços. O API Gateway fornece funcionalidades que não exigem conhecimento profundo dos domínios internos, como:

  • Proxy reverso: direciona solicitações recebidas para o serviço interno apropriado
  • Controle de versão: uma versão do API Gateway é mapeada para diferentes versões dos serviços internos
  • Autenticação: as solicitações do cliente incluem o token emitido pelo Identity Server e o API Gateway valida o token (verifique se o usuário é quem diz que é)
  • Limitação: número limite de solicitações por cliente

Autorização

No que diz respeito à autorização, isso não é gerenciado no API Gateway, mas nos próprios serviços internos. No momento, estamos fazendo dois tipos principais de autorizações:

  • Autorização com base nos escopos do cliente. Exemplo: um cliente (aplicativo externo consumindo nossas APIs) requer o escopo "reservas" para acessar os pontos de extremidade da API do serviço Reservas
  • Autorização com base no cliente. Exemplo: somente se um cliente (pessoa física que usa o aplicativo) for participante de uma reserva pode acessar o ponto de extremidade GET / bookings no serviço de Bookings

Para poder manipular a autorização nos serviços internos, o API Gateway simplesmente encaminha o token (ao rotear a solicitação para o serviço interno), que inclui informações sobre o cliente (o aplicativo que está fazendo a solicitação) e o cliente como uma reivindicação (em casos em que uma pessoa está logada no aplicativo cliente).

Descrição do Problema

Até aqui tudo bem até introduzirmos a comunicação entre serviços (alguns serviços podem se comunicar com outros serviços para obter alguns dados).

Questão

Como devemos abordar a autorização nas comunicações entre serviços?

Opções consideradas

Para discutir as diferentes opções, usarei o seguinte cenário de exemplo:

  • Temos um aplicativo externo chamado ExternalApp que acessa nossa API ( ExternalApp pode ser visto como o cliente ) para criar o fluxo de reserva
  • ExternalApp precisa acessar o serviço Reservas , portanto, concedemos ao ExternalApp o escopo "reservas"
  • Internamente (isso é algo completamente transparente para o ExternalApp ), o serviço de Reservas acessa o serviço de Serviços para obter os serviços padrão de uma reserva, como voos, seguros ou aluguel de carro

Ao discutir esse problema internamente, várias opções apareceram, mas não temos certeza de qual opção é a melhor:

  1. Quando o Bookings se comunica com os Serviços , ele deve simplesmente encaminhar o token original que ele recebeu do API Gateway (indicando que o cliente é o ExternalApp )
    • Implicações: Talvez seja necessário conceder escopos ao ExternalApp que não deveriam ter sido concedidos. Exemplo: o ExternalApp pode precisar ter o escopo "reservas" e "serviços", enquanto apenas o escopo "reservas" pode ter sido suficiente
  2. Quando o Bookings se comunica com os Serviços , ele encaminha um token indicando que o cliente agora se tornou Bookings (em vez do ExternalApp ) + adiciona uma declaração indicando que o Bookings está representando o cliente original ExternalApp
    • Ao incluir também as informações de que o cliente original é o ExternalApp, o serviço de Serviços também pode fazer lógica, como filtrar alguns serviços, dependendo do chamador original (por exemplo, para aplicativos internos, devemos retornar todas as brigas, para aplicativos externos apenas alguns)
  3. Os serviços não devem se comunicar (por isso, não devemos nem estar enfrentando essa pergunta)

Agradecemos antecipadamente a sua contribuição.

Josep Serra
fonte
1
Como você resolveu esse problema ? Estamos em uma situação semelhante.
Varun Mehta
+1: Estou interessado em como você finalmente resolve seu problema.
Dypso 20/01
Para realizar o ponto 3 - os serviços não se comunicam entre si, você precisa de uma interface composta. Veja particular.net/blog/secret-of-better-ui-composition
stevie_c

Respostas:

3

Aconselho que você tenha um canal interno de comunicação entre os microsserviços.

Por exemplo, para usar algum intermediário de mensagens como o RabbitMQ internamente para enviar / receber ou publicar / assinar as mensagens entre microsserviços.

Em seguida, seu primeiro serviço voltado para o usuário final "no seu exemplo, o serviço de Reservas" será responsável por validar o token e autorizar o cliente a realizar essa operação específica, comunicando-se com o IdentityServer.

Em seguida, ele se comunicará com o serviço de Serviços por meio do Message broker e, nesse caso, não será necessário validar o token novamente.

Eu acho que esse modelo será mais simples e oferecerá melhor desempenho.

Wahid Bitar
fonte