0

I need to register user in the system. User cannot exist without a Role (and he surely cannot exist without login and password). Administrator is supposed to be able to add new users by selecting role, writing login/password and some user information. Login/password/security concerns are implemented as separate application/BC (authentication context), roles and permissions are in authorization context and user information is in separate account management context. How can I implement user registration process if all these contexts could be in theory deployed on separate machines? For now I'm using application interface that uses infrastructure service implementation to synchronously and atomically send all needed commands to different BCs (currently it is the same big application).

Картинка

Ivan Zyranau
  • 879
  • 2
  • 14
  • 33
  • Is you question "how to integrate all those services"? – Constantin Galbenu Mar 12 '17 at 17:05
  • 1
    Kind of. It's "how to register a user?". If I send registration command to one of the bounded contexts, User aggregate root from this context will raise an event that will propagate throughout some bus and eventually make all bounded contexts consistent. But to be able to do so, I need to create some kind of integration context that will have a user registration command with all needed data for all those contexts... and I need to somehow store state, etc. Lots of overcomplication emerges, I just want a simple architectural answer. – Ivan Zyranau Mar 12 '17 at 18:01
  • 1
    "Atomically" and "multiple bounded contexts" are mutually exclusive. – Constantin Galbenu Mar 12 '17 at 19:25
  • Possible duplicate of [Communicating between two Bounded Contexts in DDD](http://stackoverflow.com/questions/16713041/communicating-between-two-bounded-contexts-in-ddd) – guillaume31 Mar 13 '17 at 08:57
  • Can you choose a solution from the given answers? – Constantin Galbenu Feb 21 '18 at 08:17

3 Answers3

2

A simple architectural answer: Use a Saga (or a Process Manager) that orchestrates all this.

You have an architecture that consists on three microservices. There are two stiles to integrate microservices: Orchestration and Choreography. A Saga uses orchestration.

Read more on SO about the differences between them.

Update: I think that Account management should be the master BC. Here the user is born, initially without a role or a meaning to authenticate. Then, it is given a role, a purpose and after that, after it is setup, a username and a pasword. This should be the sequence.

Community
  • 1
  • 1
Constantin Galbenu
  • 16,951
  • 3
  • 38
  • 54
  • Where will this `Saga` live? Should I create `Integration bounded context` that will define this Saga and related Command? (in other words, who should be responsible for starting the Saga? User should be able to fill in all needed fields in UI) – Ivan Zyranau Mar 12 '17 at 18:43
  • In which bounded context is this entity first created? The commands need to reach an `Aggregate` first, not a `Saga`; a `Saga` only listen for `events` and generate/dispatch new `commands`, it does not handle `commands`. So, think where you do send the first `command`. Where do this `Saga` lives depends on your microservices distributions. I think it could live anywhere as long as it can listen to all relevant `events` and can dispatch orchestration `commands`. – Constantin Galbenu Mar 12 '17 at 18:50
  • That's what I am trying to find out. User cannot be registered without a role (business rule), but at the same time nor can he be registered without username/password (especially considering security concerns, where if we register user in Authorization Context first, we'll need to store password somewhere (and send it in commands/events through the wire unhashed). – Ivan Zyranau Mar 12 '17 at 19:07
  • You should hash the passwords as soon as possible, i.e. before the command executes. – Constantin Galbenu Mar 12 '17 at 19:13
  • I think that `Account management` should be the master BC. Here the user is born, initially without a role or a meaning to authenticate. Then, it is given a role, a purpose and after that, after it is setup, a username and a pasword. This should be the sequence. – Constantin Galbenu Mar 12 '17 at 19:17
  • So, `Account management` BC should be aware about `userName`, `passwordHash` and `role` concepts even though they are not present in the `User` aggregate root in `Account management` BC? Or maybe `User` aggregate root in `Account management` BC should contain those fields? – Ivan Zyranau Mar 12 '17 at 20:54
  • No. A `Saga` should know how to create all the relevant Commands. But a Saga does not strictly belong to a single BC. It connects them. – Constantin Galbenu Mar 12 '17 at 21:26
  • But `Saga` should be instaniated by event, so event raised by `Account management` context should contain all the relevant data needed in order to create `User` in all other BCs... – Ivan Zyranau Mar 13 '17 at 03:46
  • I never did this but you could send a composite command to a `Saga` – Constantin Galbenu Mar 15 '17 at 07:40
2

It may be that you have gone down to a too fine degree of granularity with your bounded contexts. An indication of this is usually when the concept you are referring is the exact same thing in more than one bounded context.

Things like User management (registration / authentication / authorization) is typically handled by an Identity & Access Control Bounded Context.

That User would have different meanings / concepts in your downstream bounded contexts: e.g. Author, Supervisor, etc.

However, if you are sure that you want that level of granularity then you are going to have to pick a system of record for your user and that bounded context would own the user and be responsible for the process manager state and seeing the registration through to completion; although, I usually like to have my process management as a bounded context in and of itself and it can orchestrate among the others.

As for doing so atomically... I don't know whether this would necessarily be wise to attempt :)

Eben Roux
  • 12,983
  • 2
  • 27
  • 48
0

You'd need a distributed transaction server for that. Java has a standard for distributed transactions (JTA).

M. le Rutte
  • 3,525
  • 3
  • 18
  • 31