web-dev-qa-db-fra.com

SOA / Microservices: comment gérer les autorisations dans les communications interservices?

Premier plan

Nous passons d'une plate-forme monolithique à une architecture davantage orientée services. Nous appliquons des principes DDD très basiques et divisons notre domaine dans différents contextes bornés. Chaque domaine est distribué et expose un service via une API web (REST).

En raison de la nature de notre entreprise, nous avons des services tels que Réservations, Services, Clients, Produits, etc.

Nous avons également mis en place un Identity Server (basé sur Thinktecture Identity Server 3) dont le rôle principal est de:

  • Centraliser l'authentification (compte tenu des informations d'identification, il émet des jetons)
  • Ajoutez des revendications dans les jetons tels que: l'étendue du client (par client, je veux dire l'application qui fait la demande), l'identifiant du client (par client, je veux dire la personne qui utilise l'application)

Nous avons également introduit le rôle d'une API Gateway qui centralise l'accès externe à nos services. API Gateway fournit des fonctionnalités qui ne nécessitent pas une connaissance approfondie des domaines internes tels que:

  • Proxy inverse: achemine les demandes entrantes vers le service interne approprié
  • Gestion des versions: une version de la passerelle API correspond à différentes versions des services internes
  • Authentification: les demandes des clients incluent le jeton émis par Identity Server et la passerelle API valide le jeton (assurez-vous que l'utilisateur est bien celui qui le dit)
  • Limitation: limiter le nombre de demandes par client

Autorisation

En ce qui concerne l'autorisation, celle-ci n'est pas gérée dans l'API Gateway mais dans les services internes lui-même. Nous effectuons actuellement 2 principaux types d'autorisations:

  • Autorisation basée sur les étendues du client. Exemple: un client (application externe consommant nos API) a besoin de la portée "réservations" pour accéder aux points de terminaison de l'API de service Réservations
  • Autorisation basée sur le client. Exemple: uniquement si un client (personne physique utilisant l'application) participant à une réservation peut accéder au point de terminaison GET/réservations depuis le service Réservations

Pour pouvoir gérer l'autorisation dans les services internes, l'API Gateway transfère simplement le jeton (lors du routage de la demande vers le service interne) qui comprend à la fois des informations sur le client (l'application qui fait la demande) et le client en tant que réclamation (dans les cas où une personne est connectée dans l'application client).

Description du problème

Jusqu'ici tout va bien jusqu'à ce que nous introduisions la communication interservices (certains services peuvent communiquer avec d'autres services pour obtenir des données).

Question

Comment aborder l'autorisation dans les communications interservices?

Options envisagées

Pour discuter des différentes options, j'utiliserai l'exemple de scénario suivant:

  • Nous avons une application externe appelée ExternalApp qui accède à notre API ( ExternalApp peut être vue comme le client) afin de construire le flux de réservation
  • ExternalApp a besoin d'accéder au service Réservations, nous accordons donc au ExternalApp la portée "réservations"
  • En interne (c'est quelque chose de complètement transparent pour le service ExternalApp) Réservations accède au service Services pour obtenir les services par défaut d'une réservation comme les vols, les assurances ou la location de voiture

Lorsque vous discutez de ce problème en interne, plusieurs options sont apparues, mais nous ne savons pas quelle option est la meilleure:

  1. Lorsque Réservations communique avec Services, il doit simplement transmettre le jeton d'origine qu'il a reçu de la passerelle API (indiquant que le client est le ExternalApp)
    • Implications: nous pourrions avoir besoin d'accorder des étendues à ExternalApp qui n'auraient pas dû être accordées. Exemple: ExternalApp peut avoir besoin d'avoir à la fois la portée "bookings" et "services" alors que seule la portée "bookings" aurait pu suffire
  2. Lorsque Réservations communique avec Services, il transmet un jeton indiquant que le client est devenu Réservations (au lieu de ExternalApp) + il ajoute une réclamation indiquant Réservations usurpe l'identité du client d'origine ExternalApp
    • En incluant également les informations selon lesquelles le client d'origine est le service ExternalApp le service Services pourrait également faire de la logique, comme filtrer certains services en fonction de l'appelant d'origine (par exemple pour les applications internes, nous devons renvoyer tous les combats, pour les applications externes seulement certains)
  3. Les services ne devraient pas communiquer entre eux (nous ne devrions donc même pas être confrontés à cette question)

Merci d'avance pour votre contribution.

20
Josep Serra

Je vous conseille d'avoir un interne canal de communication entre les microservices.

Par exemple, pour utiliser courtier de messages comme RabbitMQ en interne à envoyer/recevoir ou publier/s'abonner les messages entre les microservices.

Ensuite, votre premier utilisateur face au service "dans votre exemple, le service de réservation" sera chargé de valider le jeton et d'autoriser le client à effectuer cette opération spécifique en communiquant avec IdentityServer.

Ensuite, il communiquera avec le service Services via Message Broker et dans ce cas, il n'est pas nécessaire de valider à nouveau le jeton.

Je suppose que ce modèle sera plus simple et vous donnera de meilleures performances.

3
Wahid Bitar