17

I'm looking into crafting an app with DDD+CQRS+EventSourcing, and I have some trouble figuring out how to do user auth.

Users are intrinsically part of my domain, as they are responsible for clients. I'm using ASP.NET MVC 4, and I was looking to just use the SimpleMembership. Since logging in and authorising users is a synchronous operation, how is this tackled in an eventually consistent architecture?

Will I have to roll my own auth system where I keep denormalized auth tables on the read side? How to handle the security of this? Will I end up storing password hashes in both my event store and my view tables?

So many questions, if anyone can shed some light, I would be very thankful :)

tldr; How do you do User Auth in EventSource-applications?

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
tuxbear
  • 551
  • 4
  • 13
  • The same way you do it in message based systems, AFAIK. You seem to mix authorization & authentication. What is it you are trying to secure? – Yves Reynhout Mar 26 '13 at 21:25
  • I'm not mixing them, I'm asking about both, really :) Seems my main problem then is that I don't know how it's done in message based systems ;) – tuxbear Mar 29 '13 at 09:14

3 Answers3

14

Not every "Domain" or business component has to use DDD or CQRS. In most cases, user information is really cruddy, so you can usually not use DDD for that. Other domains don't really depend on the actual user. There's usually a correlation id (UserId) that gets shared by the various domains.

If using messaging in your system, one option is to register and manage users without CQRS, then send a command (RegisterUser { UserId } ). This would publish an event User Registered. Other domains can listen to this event to kick-off any workflows or ARs that are needed.

Jonathan Matheus
  • 1,350
  • 2
  • 12
  • 15
  • 2
    +1 I second that.. its not all CQRS or nothing.. pick and choose where it make sense. for us, we authenticate the user and issue a token, which we can then assign to the header of each command to ensure the user has the correct access levels and credentials to perform certain operations within the context of the command. – Sarmaad Mar 27 '13 at 12:56
  • 4
    Thank you! I think this actually is the answer I'm looking for. I was thinking about this solution, but it seems kinda dirty to have some data in the event store, and some data in db-tables. I'm also concerned about the ability to replay event to restore state, as this benefit of EventSouring is the sole reason why I'm exploring it. It also concerns me that there is some cognitive overhead of having two architectures side by side like that. – tuxbear Mar 29 '13 at 09:17
12

For our MVC CQRS app, we originally started off keeping all the user related information in the domain, and, like somebody mentioned, there was a RegisterUserCommand and a UserRegisteredEvent. After storing the user information in the domain, that event got published and picked up on the read side, which also created a user and generated all the password hashes, etc. We then done the authentication on the read side: the controller would make a call out to a 'read model authentication service' to authenticate against.

Later on down the road, we ended up completely refactoring this. It turned out that we needed access to the user related information to build in security for authorising our commands, which we done on the command processing side (our app is a distributed app that sends 'fire and forget' asynchronous commands to a queue, with an autonomous listener on the other side). The security component then needed a reference to our domain to go and get the user profile, which led to cumbersome referencing issues.

We decided to put the user security stuff into a separate database that we considered to be more of a central component, rather than belonging to the domain or read model. We still maintain user profile related information in the domain and read models (e.g. job title, twitter account URL etc.), but all the security related stuff, like password hashes, are stored in this central database. That's then accessible with a service, that's available to both MVC and the command authoriser.

We didn't actually have to change anything in the UI for this refactor, as we just called the service to register the users from the register user command handler. If you're going to do it that way, you need to be careful here to make your user service related operations idempotent. This is so that you can give your commands the opportunity to be retried without side effects, because you're updating 2 sources of information (the ES and the user database).

Finally, you could of course use the membership providers for this central component, but there can be pitfalls with that. We ended up just writing our own - it's pretty simple to do. That article links to this, which provides a good example of how to implement it.

jacderida
  • 565
  • 1
  • 4
  • 14
  • Thank you! I would've gone down this path also, good to get some advice from people with actual experience using these constructs. My big turn on with ES is the ability to build new features with old information. Have the storage of domain data as events proven valuable to you? – tuxbear Mar 29 '13 at 09:24
  • 1
    Yeah, because it means that you can regenerate the security stuff by replaying the ES. – jacderida Mar 30 '13 at 17:48
  • What you describe is simply using one more [projection](http://abdullin.com/event-sourcing/projections.html) to handle your domain events. It is really very easy, thanks! So using realtime or stale data just depends on when you snychronize your read model with your events, nothing more... – inf3rno Apr 23 '14 at 04:57
1

You should consider creating separate entities like: visitor (just visited your site), user (registered), customer (bought something), etc. Try to split your system in this way, even if it causes a little bit of data redundancy. Disk space is not an issue but ability to modify different components of the system independently is usually very critical.

People create denormalized auth tables only for the purpose of scaling and only if your auth read side is a performance bottleneck. If not - usual 3rd normal form is a way to go.

In SimpleMembership scenario all tables created by SimpleMembership can be viewed as snapshot of "user" aggregate. And yes, they will duplicate some data in your event store. You may have events like: UserCreated, UserUpdated, UserAssignedToRole, etc.

And don't be tricked by the name of that membership provider. It's not so simple and usually has lots of things that you can easily live without (depends on your domain). So, maybe you can use something like this: https://gist.github.com/Kayli/fe73769f19fdff40c3a7

IlliakaillI
  • 1,510
  • 13
  • 25