12

Zajmuję się tworzeniem aplikacji z DDD + CQRS + EventSourcing, i mam problem z ustaleniem, jak wykonać autoryzację użytkownika.Autoryzacja użytkownika w aplikacjach EventSourcing

Użytkownicy są nieodłączną częścią mojej domeny, ponieważ są odpowiedzialni za klientów. Używam ASP.NET MVC 4, a ja chciałem po prostu użyć SimpleMembership. Od kiedy logowanie i autoryzacja użytkowników jest operacją synchroniczną, w jaki sposób jest ona rozwiązywana w ostatecznie spójnej architekturze?

Czy będę musiał przetasować własny system autoryzacji, w którym będę przechowywać zdenormalizowane tabele auth po stronie odczytu? Jak sobie z tym poradzić? Czy będę przechowywać skróty hasłowe zarówno w moim magazynie zdarzeń, jak i w tabelach widoków?

Tak wiele pytań, czy ktoś może rzucić nieco światła, byłbym bardzo wdzięczny :)

tldr; Jak wykonujesz autoryzację użytkownika w aplikacjach EventSource?

+0

Tak samo, jak w przypadku systemów opartych na komunikatach, AFAIK. Wygląda na to, że mieszasz autoryzację i autoryzację. Co próbujesz zabezpieczyć? –

+0

Nie mieszam ich, pytam o oba, naprawdę :) Wydaje się, że moim głównym problemem jest to, że nie wiem, jak to się robi w systemach opartych na komunikatach;) – tuxbear

Odpowiedz

9

Nie każda "domena" lub składnik biznesowy musi korzystać z DDD lub CQRS. W większości przypadków informacje o użytkowniku są bardzo proste, więc zazwyczaj nie można do tego użyć DDD. Inne domeny w rzeczywistości nie zależą od rzeczywistego użytkownika. Zwykle istnieje identyfikator korelacji (UserId), który jest udostępniany przez różne domeny.

Jeśli używasz wiadomości w systemie, jedną z opcji jest rejestracja użytkowników i zarządzanie nimi bez CQRS, a następnie wysłanie polecenia (RegisterUser {UserId}). Spowoduje to opublikowanie wydarzenia Zarejestrowany użytkownik. Inne domeny mogą nasłuchiwać tego zdarzenia, aby rozpocząć wszystkie przepływy pracy lub wymagane AR.

+2

+1 I sekunda, że ​​.. to nie wszystko CQRS lub nic ... wybierz i wybierz, gdzie ma to sens. dla nas uwierzytelniamy użytkownika i wydajemy token, który możemy następnie przypisać do nagłówka każdego polecenia, aby zapewnić, że użytkownik ma odpowiednie poziomy dostępu i referencje do wykonywania określonych operacji w kontekście polecenia. – Sarmaad

+2

Dziękujemy! Myślę, że to właśnie jest odpowiedź, której szukam. Myślałem o tym rozwiązaniu, ale wydaje się trochę brudne mieć pewne dane w magazynie zdarzeń, a niektóre dane w tabelach db. Martwi mnie również możliwość odtworzenia zdarzenia w celu przywrócenia stanu, ponieważ ta korzyść z EventSouring jest jedynym powodem, dla którego go eksploruję. Obawiam się również, że niektóre funkcje poznawcze wiążą się z dwoma podobnymi architekturami. – tuxbear

0

Powinieneś rozważyć utworzenie oddzielnych elementów, takich jak: odwiedzający (właśnie odwiedził twoją witrynę), użytkownik (zarejestrowany), klient (kupił coś), itp. Spróbuj podzielić system w ten sposób, nawet jeśli powoduje to trochę nadmiarowość danych. Miejsce na dysku nie stanowi problemu, ale umiejętność samodzielnego modyfikowania różnych komponentów systemu jest zazwyczaj bardzo istotna.

Osoby tworzą denormalizowane tabele auth tylko w celu skalowania i tylko wtedy, gdy strona z auth do odczytu jest wąskim gardłem wydajności. Jeśli nie - zwykła trzecia normalna forma to sposób na odejście.

W scenariuszu SimpleMembership wszystkie tabele utworzone przez SimpleMembership można wyświetlić jako migawkę agregatu "user". I tak, będą duplikować niektóre dane w twoim magazynie zdarzeń. Możesz mieć zdarzenia takie jak: UserCreated, UserUpdated, UserAssignedToRole, itp.

I nie dajcie się zwieść nazwie tego dostawcy członkostwa. To nie jest takie proste i zwykle zawiera wiele rzeczy, które bez problemu można przeżyć (zależy od Twojej domeny). Może więc możesz użyć czegoś takiego: https://gist.github.com/Kayli/fe73769f19fdff40c3a7

9

Dla naszej aplikacji CQRS MVC, początkowo zaczęliśmy przechowywać wszystkie informacje związane z użytkownikiem w domenie i, jak ktoś wspomniał, było RegisterUserCommand i UserRegisteredEvent. Po zapisaniu informacji o użytkowniku w domenie, to wydarzenie zostało opublikowane i odebrane po stronie odczytu, które również utworzyło użytkownika i wygenerowało wszystkie skróty haseł itp. Następnie wykonaliśmy autoryzację po stronie odczytu: kontroler wykona wywołać "usługę uwierzytelniania modelu odczytu" w celu uwierzytelnienia.

Później w dół drogi, skończyliśmy całkowicie refaktoryzować to. Okazało się, że potrzebujemy dostępu do informacji związanych z użytkownikiem, aby zbudować zabezpieczenia do autoryzacji naszych poleceń, które wykonaliśmy po stronie przetwarzania poleceń (nasza aplikacja jest rozproszoną aplikacją, która wysyła "ogień i zapomnij" asynchroniczne polecenia do kolejki, z niezależny słuchacz po drugiej stronie). Komponent bezpieczeństwa wymagał wówczas odwołania do naszej domeny, aby uzyskać profil użytkownika, co doprowadziło do kłopotliwych problemów z odniesieniami.

Zdecydowaliśmy się umieścić elementy bezpieczeństwa użytkownika w oddzielnej bazie danych, która uważana jest za bardziej centralny komponent, niż przynależność do domeny lub modelu odczytu. Wciąż przechowujemy informacje związane z profilem użytkownika w domenie i czytamy modele (np. Tytuł stanowiska, adres URL konta Twitter itp.), Ale wszystkie informacje związane z bezpieczeństwem, takie jak hashy, są przechowywane w tej centralnej bazie danych. To jest wtedy dostępne dzięki usłudze, która jest dostępna zarówno dla MVC, jak i dla autoryzatora poleceń.

W rzeczywistości nie musieliśmy niczego zmieniać w interfejsie tego refaktora, ponieważ właśnie nazwaliśmy usługę, aby zarejestrować użytkowników z obsługi komend użytkownika rejestru. Jeśli zamierzasz to zrobić w ten sposób, musisz zachować ostrożność, aby operacje związane z obsługą użytkowników były idempotentne. To jest tak, że możesz dać swoim komendom możliwość ponownej próby bez efektów ubocznych, ponieważ aktualizujesz 2 źródła informacji (ES i bazę danych użytkowników).

Wreszcie można oczywiście użyć dostawców członkostwa dla tego komponentu centralnego, ale z tym może być pitfalls. Skończyło się na tym, że napisaliśmy własne - jest to całkiem proste. Ten artykuł zawiera link do strony this, która jest dobrym przykładem tego, jak ją zaimplementować.

+0

Dziękujemy! Poszedłbym również tą drogą, dobrze, aby uzyskać porady od ludzi z rzeczywistymi doświadczeniami z wykorzystaniem tych konstrukcji. Mój wielki zwrot z ES to możliwość budowania nowych funkcji ze starymi informacjami. Czy przechowujesz dane domeny jako zdarzenia, które okazały się dla ciebie wartościowe? – tuxbear

+1

Tak, ponieważ oznacza to, że możesz odtworzyć zabezpieczenia, odtwarzając ES. – jacderida

+0

To, co opisujesz, to po prostu użycie jeszcze jednej [projekcji] (http://abdullin.com/event-sourcing/projections.html) do obsługi wydarzeń w domenie. To naprawdę bardzo proste, dzięki! Używanie danych w czasie rzeczywistym lub starych zależy od tego, kiedy snieronizujesz swój model czytania ze swoimi zdarzeniami, nic więcej ... – inf3rno