SOA / Microservices: Jak obsługiwać autoryzację w komunikacji między usługami?

18

Pierwszoplanowy

Przechodzimy z platformy monolitycznej do architektury zorientowanej na usługi. Stosujemy bardzo podstawowe zasady DDD i dzielimy naszą domenę na różne ograniczone konteksty. Każda domena jest dystrybuowana i udostępnia usługę za pośrednictwem interfejsu API sieci Web (REST).

Ze względu na charakter naszej działalności, mamy takie usługi jak rezerwacjach , usług , klientów , produktów , itp

Stworzyliśmy również serwer tożsamości (oparty na Thinktecture Identity Server 3), którego główną rolą jest:

  • Scentralizuj uwierzytelnianie (dane uwierzytelniające wydaje tokeny)
  • Dodaj oświadczenia do tokenów, takie jak: zakresy klienta (jak na klienta, mam na myśli aplikację wykonującą żądanie), identyfikator klienta (na klienta, mam na myśli osobę korzystającą z aplikacji)

Wprowadziliśmy również rolę API Gateway, która centralizuje zewnętrzny dostęp do naszych usług. API Gateway zapewnia funkcjonalności, które nie wymagają dogłębnej znajomości domen wewnętrznych, takie jak:

  • Odwrotny serwer proxy: kieruje przychodzące żądania do odpowiedniej usługi wewnętrznej
  • Wersjonowanie: wersja interfejsu API Gateway odwzorowuje różne wersje usług wewnętrznych
  • Uwierzytelnianie: żądania klientów zawierają token wydany przez serwer tożsamości, a brama API sprawdza token (upewnij się, że użytkownik jest tym, kto twierdzi, że jest)
  • Ograniczanie: ogranicz liczbę żądań na klienta

Upoważnienie

Co dotyczy autoryzacji, nie jest ona zarządzana w bramce API, ale w samych usługach wewnętrznych. Obecnie wykonujemy 2 główne rodzaje autoryzacji:

  • Autoryzacja na podstawie zakresów klienta. Przykład: klient (zewnętrzna aplikacja zużywa nasze API) wymaga zakresu „rezerwacje” na dostęp do rezerwacji hoteli usługowa punktów końcowych API
  • Autoryzacja na podstawie klienta. Przykład: jeśli tylko klient (osoba fizyczna przy użyciu aplikacji) jest uczestnikiem rezerwacji można uzyskać dostęp do punktu końcowego GET / rezerwacje od Kartki usługi

Aby móc obsługiwać autoryzację w usługach wewnętrznych, brama API po prostu przekazuje token (podczas routingu żądania do usługi wewnętrznej), który zawiera zarówno informacje o kliencie (aplikacji wykonującej żądanie), jak i kliencie jako roszczenie (w przypadki, w których osoba jest zalogowana w aplikacji klienckiej).

Opis problemu

Jak dotąd tak dobrze, dopóki nie wprowadziliśmy komunikacji między usługami (niektóre usługi mogą komunikować się z innymi usługami w celu uzyskania niektórych danych).

Pytanie

Jak powinniśmy podejść do autoryzacji w komunikacji między usługami?

Rozważane opcje

Aby omówić różne opcje, wykorzystam następujący przykładowy scenariusz:

  • Mamy zewnętrzną aplikację o nazwie ExternalApp, która uzyskuje dostęp do naszego interfejsu API ( ExternalApp może być postrzegany jako klient ) w celu zbudowania przepływu rezerwacji
  • ExternalApp potrzebuje dostępu do usługi Bookings , dlatego przyznajemy ExternalApp zakres „rezerwacji”
  • Wewnętrznie (jest to coś całkowicie przezroczysty dla ExternalApp ) Kartki serwis acesses Services usługę w celu uzyskania usługi domyślne rezerwacji takich jak loty, ubezpieczeniach lub wynajem samochodu

Podczas wewnętrznego omawiania tego problemu pojawiło się kilka opcji, ale nie jesteśmy pewni, która opcja jest najlepsza:

  1. Gdy Bookings komunikuje się z Usługami , powinien po prostu przesłać oryginalny token, który otrzymał od API Gateway (wskazując, że klient jest aplikacją zewnętrzną )
    • Konsekwencje: być może będziemy musieli przyznać zakresy aplikacji zewnętrznej, które nie powinny były zostać przyznane. Przykład: ExternalApp może wymagać zarówno zakresu „rezerwacji”, jak i „usług”, podczas gdy wystarczyłby tylko zakres „rezerwacji”
  2. Gdy Bookings komunikuje się z Usługami , przesyła token wskazujący, że klient stał się Bookings (zamiast ExternalApp ) + dodaje roszczenie wskazujące, że Bookings podszywa się pod oryginalnego klienta ExternalApp
    • Włączając również informacje, że oryginalny klient jest ExternalApp z Usługi obsługa mogłaby również zrobić logiki takich jak filtrowanie niektórych usług w zależności od pierwotnego dzwoniącego (np wewnętrznych aplikacji powinniśmy zwrócić wszystkie pojedynki, dla zewnętrznych aplikacji tylko niektóre)
  3. Usługi nie powinny się ze sobą komunikować (więc nie powinniśmy nawet stawiać czoła temu pytaniu)

Z góry dziękuję za Twój wkład.

Josep Serra
źródło
1
Jak rozwiązałeś ten problem? Jesteśmy w podobnej sytuacji.
Varun Mehta
+1: Jestem zainteresowany tym, jak w końcu rozwiązujesz swój problem.
Dypso
Aby wykonać punkt 3 - usługi nie komunikują się ze sobą, potrzebujesz złożonego interfejsu użytkownika. Patrz konkretnie.net/blog/secret-of-better-ui-composition
stevie_c

Odpowiedzi:

3

Radzę mieć wewnętrzny kanał komunikacji między mikrousługami.

Na przykład, aby użyć wewnętrznego brokera wiadomości, takiego jak RabbitMQ, do wysyłania / odbierania lub publikowania / subskrybowania wiadomości między mikrousługami.

Wtedy Twoja pierwsza usługa skierowana do użytkownika końcowego „na przykład usługa rezerwacji” będzie odpowiedzialna za sprawdzenie tokena i upoważnienie klienta do wykonania tej konkretnej operacji może być przez komunikację z IdentityServer.

Następnie komunikuje się z usługą za pośrednictwem brokera wiadomości, w takim przypadku nie ma potrzeby ponownej weryfikacji tokena.

Myślę, że ten model będzie prostszy i zapewni lepszą wydajność.

Wahid Bitar
źródło