Пользовательская аутентификация в приложениях EventSourcing

Я собираюсь создать приложение с помощью DDD + CQRS + EventSourcing, и у меня возникли проблемы с тем, чтобы понять, как выполнить аутентификацию пользователя.

Пользователи являются неотъемлемой частью моего домена, поскольку они несут ответственность за клиентов. Я использую ASP.NET MVC 4, и я хотел просто использовать SimpleMembership. Поскольку вход в систему и авторизация пользователей являются синхронной операцией, как это решается в согласованной в конечном итоге архитектуре?

Придется ли мне использовать собственную систему аутентификации, в которой я буду хранить денормализованные таблицы аутентификации на стороне чтения? Как обеспечить безопасность этого? Смогу ли я в конечном итоге хранить хэши паролей как в моем хранилище событий, так и в моих таблицах просмотра?

Так много вопросов, если кто-нибудь сможет пролить свет, буду очень благодарен :)

tldr; Как вы делаете User Auth в EventSource-приложениях?


person tuxbear    schedule 26.03.2013    source источник
comment
Точно так же, как вы делаете это в системах на основе сообщений, AFAIK. Кажется, вы смешиваете авторизацию и аутентификацию. Что вы пытаетесь обезопасить?   -  person Yves Reynhout    schedule 27.03.2013
comment
Я не смешиваю их, я спрашиваю об обоих, правда :) Кажется, моя основная проблема в том, что я не знаю, как это делается в системах, основанных на сообщениях;)   -  person tuxbear    schedule 29.03.2013


Ответы (3)


Не каждый «домен» или бизнес-компонент должен использовать DDD или CQRS. В большинстве случаев информация о пользователях действительно неаккуратна, поэтому вы обычно не можете использовать для этого DDD. Другие домены на самом деле не зависят от реального пользователя. Обычно существует идентификатор корреляции (UserId), который используется разными доменами.

Если в вашей системе используется обмен сообщениями, одним из вариантов является регистрация и управление пользователями без CQRS, а затем отправка команды (RegisterUser {UserId}). Это опубликует событие, зарегистрированное пользователем. Другие домены могут прослушивать это событие, чтобы запустить любые необходимые рабочие процессы или AR.

person Jonathan Matheus    schedule 26.03.2013
comment
+1 Во-вторых, это не все CQRS или ничего .. выбирай и выбирай, где это имеет смысл. для нас мы аутентифицируем пользователя и выпускаем токен, который затем можем назначить заголовку каждой команды, чтобы гарантировать, что у пользователя есть правильные уровни доступа и учетные данные для выполнения определенных операций в контексте команды. - person Sarmaad; 27.03.2013
comment
Спасибо! Я думаю, что это именно тот ответ, который я ищу. Я думал об этом решении, но кажется немного грязным иметь некоторые данные в хранилище событий и некоторые данные в db-таблицах. Меня также беспокоит возможность воспроизвести событие для восстановления состояния, поскольку это преимущество EventSouring - единственная причина, по которой я его исследую. Меня также беспокоит то, что наличие двух подобных архитектур бок о бок сопряжено с некоторыми когнитивными издержками. - person tuxbear; 29.03.2013

Для нашего приложения MVC CQRS мы изначально начали с хранения всей информации, связанной с пользователем, в домене, и, как кто-то упомянул, были RegisterUserCommand и UserRegisteredEvent. После сохранения информации о пользователе в домене это событие было опубликовано и перехвачено на стороне чтения, что также создало пользователя и сгенерировало все хэши паролей и т. Д. Затем мы провели аутентификацию на стороне чтения: контроллер выполнял вызвать «службу проверки подлинности модели чтения» для проверки подлинности.

Позже мы закончили его полным рефакторингом. Оказалось, что нам нужен доступ к информации, связанной с пользователем, чтобы обеспечить безопасность для авторизации наших команд, что мы и сделали на стороне обработки команд (наше приложение представляет собой распределенное приложение, которое отправляет асинхронные команды «запустить и забыть» в очередь с автономный слушатель с другой стороны). Затем компоненту безопасности потребовалась ссылка на наш домен, чтобы получить профиль пользователя, что привело к обременительным проблемам со ссылками.

Мы решили поместить информацию о безопасности пользователей в отдельную базу данных, которую мы считали скорее центральным компонентом, нежели принадлежащим домену или модели чтения. Мы по-прежнему поддерживаем информацию, связанную с профилем пользователя, в домене и моделями чтения (например, название должности, URL-адрес учетной записи Twitter и т. Д.), Но все связанные с безопасностью вещи, такие как хэши паролей, хранятся в этой центральной базе данных. Затем это становится доступным с помощью службы, доступной как для MVC, так и для авторизатора команд.

На самом деле нам не пришлось ничего менять в пользовательском интерфейсе для этого рефакторинга, поскольку мы просто вызвали службу для регистрации пользователей из обработчика команд register user. Если вы собираетесь сделать это таким образом, вам нужно быть осторожным, чтобы сделать операции, связанные с пользовательскими сервисами, идемпотентными. Это сделано для того, чтобы вы могли дать своим командам возможность повторить попытку без побочных эффектов, потому что вы обновляете 2 источника информации (ES и пользовательская база данных).

Наконец, вы, конечно, можете использовать поставщиков членства для этого центрального компонента, но может быть подводные камни с этим. В итоге мы просто написали свой - это довольно просто. В этой статье есть ссылка на this, который представляет собой хороший пример того, как это реализовать.

person jacderida    schedule 27.03.2013
comment
Спасибо! Я бы тоже пошел по этому пути, хорошо бы получить несколько советов от людей, имеющих реальный опыт использования этих конструкций. В ES меня больше всего привлекает возможность создавать новые функции с использованием старой информации. Доказали ли вы ценность хранения данных домена в виде событий? - person tuxbear; 29.03.2013
comment
Да, потому что это означает, что вы можете восстановить элементы безопасности, воспроизведя ES. - person jacderida; 30.03.2013
comment
То, что вы описываете, просто использует еще одну проекцию для обработки событий вашего домена. Это действительно очень просто, спасибо! Таким образом, использование данных в реальном времени или устаревших данных просто зависит от того, когда вы синхронизируете свою модель чтения с вашими событиями, не более того ... - person inf3rno; 23.04.2014

Вам следует подумать о создании отдельных объектов, таких как: посетитель (только что посетил ваш сайт), пользователь (зарегистрированный), покупатель (что-то купил) и т. Д. Попытайтесь разделить вашу систему таким образом, даже если это вызовет небольшую избыточность данных. Место на диске не является проблемой, но возможность изменять различные компоненты системы независимо друг от друга обычно очень важна.

Люди создают денормализованные таблицы аутентификации только с целью масштабирования и только в том случае, если ваша сторона чтения аутентификации является узким местом для производительности. Если нет, то можно использовать обычную 3-ю нормальную форму.

В сценарии SimpleMembership все таблицы, созданные SimpleMembership, можно рассматривать как моментальный снимок «пользовательского» агрегата. И да, они будут дублировать некоторые данные в вашем хранилище событий. У вас могут быть такие события, как: UserCreated, UserUpdated, UserAssignedToRole и т. Д.

И не позволяйте обмануть имя этого поставщика членства. Это не так просто, и обычно в нем есть много вещей, без которых вы легко можете жить (зависит от вашего домена). Итак, возможно, вы можете использовать что-то вроде этого: https://gist.github.com/Kayli/fe73769f19fdff40c3a7

person IlliakaillI    schedule 27.03.2013