2

While writing a solution from scratch based on microservice approach (more specifically it is Azure Service Fabric) I came to an idea of splitting the user Identity (which is login credentials, claims, etc.) and user profile (which may contain some social info like avatar, links to social networks, birthday, etc.).

For the identity, I'm going to use IdentityServer4 (stateless ASP.Net Core) and for storing all these data I'm thinking of an Entity Framework + SQL. The profile will be managed and stored on different microservice (stateless as well) with a connection to Cosmos DB (via Mongo DB API), thus making it a NoSQL storage.

Are there any disadvantages of such an approach I'm not aware of?

Andrew Nikolin
  • 297
  • 1
  • 4
  • 18

1 Answers1

3

You're conflating a bunch of things here. First, you have your actual "user" entity persisted to the database. There is no good reason to split a "profile" from this, as it's all just data about the user. If you're using Identity to manage users, roles and such, it was designed to be extensible from the ground up, meaning put user data on the user entity. A separate profile entity only serves to necessitate an join for no purpose.

At a higher level, once the user has been authenticated (via Identity Server), you have a principal. That principal is basically just a set of claims tied to a particular "identity" (i.e. the authenticated user). The claims come from multiple places, it could be data on the user record, roles, or even third-party claims such as when an external login account is utilized. Where the claims come from is mostly inconsequential.

Long and short, there's no reason for a separate profile entity and especially no reason for an entirely different service to work with profiles. That profile service would inevitably have to utilize a user service, so there's a hard dependency between the two: a clear sign that it's no a true separate service. In fact, this only makes the rest of your app that much more complicated as then you're having to work with both a user service and profile service depending on what piece of the user you're after.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Thanks for such a detailed response! From my perspective, the idea would be to avoid load in terms of request processing on IdentityServer, cause the solution is some kind of social network I'd say. So whenever somebody would request to see a user profile it'd be retrieved from a faster NoSQL storage by separate microservice, and the identity server would only handle auth work. – Andrew Nikolin Feb 27 '19 at 14:19
  • That's all happening on the backend, so NoSQL or not doesn't affect the ultimate response time, assuming everything is in the same vnet, of course. Besides, NoSQL doesn't necessarily equal "faster". It *can* be in certain scenarios under certain conditions, but SQL Server is hardly a slouch. Regardless, as far as the end-user is concerned, it's just claims on the principal returned from Identity Server, so there's virtually no difference on that end. If you want to limit what's returned, that's what scopes are far. You don't need to split your table for that. – Chris Pratt Feb 27 '19 at 14:23
  • In fact, if you want to get down to the brass tacks, using two different data sources is far more inefficient, even if the NoSQL side was "faster". If you're having to query SQL Server *anyways*, then that cost is already baked in, so all you're doing is adding additional network latency for the subsequent NoSQL store query. – Chris Pratt Feb 27 '19 at 14:25
  • No, for viewing profile I'd query only a microservice with profiles in it, so the SQL server (or anything hosting identity) wouldn't be queried at all. I'm kind of separating concerns of authenticating/authorizing users and working with user data which is assumed to be publically accessible and viewed. – Andrew Nikolin Feb 27 '19 at 14:31
  • But you're really not. Again, that's why I tried to point out the difference between the user entity and the principal. The entity is only tangentially related to authentication. It's just something you persist to authenticate against. It could be entirely in-memory for all it mattered, and in fact Identity Server handles users that way out of the box to allow you get up and running quickly. The "profile" and the "user" are the same thing from a pure data perspective. Having it all it one is essentially just having Identity Server auth against the "profile". It's all just semantics. – Chris Pratt Feb 27 '19 at 14:37
  • In other words, a user without it's profile is virtual inconsequential, so you could then remove the user and just use the profile instead, which then makes the profile your "user" and you're back where you started. – Chris Pratt Feb 27 '19 at 14:38
  • 1
    I've managed to find some links, like https://stackoverflow.com/a/947639/1666284 and https://cloud.google.com/blog/products/gcp/12-best-practices-for-user-account (items 3 and 4). Looks like they describe exactly what I'm speaking about – Andrew Nikolin Feb 27 '19 at 14:56
  • The SO answer is talking separating user data from domain data, not from other user data. User profile data, especially in this day and age of GDPR and constant data leaks, is still critical stuff to keep secure, so there's no argument for splitting from things like password. The GCP link does recommend keeping credentials separate from "account" data, but it certainly doesn't say that this is always the best or only way: it just presents it as an option. Ultimately, do what you want. It's your app. Personally, I actually find the GCP rationale lacking. – Chris Pratt Feb 27 '19 at 15:26
  • Thanks a lot! I got your point, will overthink all the options to chose the approach. This ended up in quite a long discussion :) – Andrew Nikolin Feb 27 '19 at 15:41
  • There is the use case where you have 'user' and 'profile' data that is distinct and separate from Identity (Application User). Think CRM: you have a list of prospects you'd like to turn into Application Users, but currently they don't have any authentication credentials. With GDPR, I keep profile and user data generated by Identity, separate from CRM data, even though some of the data is redundant. Email address, for example. So, if an Application User want to delete all of his/her provided data, they can remove it; The data in the CRM however, is not affected by this, and remains intact. – SRQ Coder Feb 27 '19 at 16:10
  • As far as Microservice applications are concerned, remember that each Microservice is 'supposed to' have its own data store.Given this, it's plausible to separate 'User" and "Profile" data, But that 'eventual consistency' (non query operations) is more to the point what Chris Platt describes. – SRQ Coder Feb 27 '19 at 16:20
  • @SRQCoder Yea, I agree that they should have separate data stores, and that's what I've described in the initial post. Your CRM example is the same I think my solution will have, another idea of feature development may be to manage multiple "profiles" with one identity user, so I guess in such case the described approach suites best. – Andrew Nikolin Feb 27 '19 at 19:44
  • 1
    Our IDS4 implementation serves a wide range of applications, each with their own idea of what a user or person entity is and each with extensive profile information stored. Our IDS4 does not concern itself with any of this and serves ONLY to support authentication. Separately we have a SaaS platform which has a concept of tenants/organisations and members and these members filter down into the products which are integrated into that platform (not all are). So the long answer is - it depends what your world looks like what makes sense but don't make it hard for yourself for no reason. – mackie Feb 28 '19 at 18:39
  • 1
    @mackie: Well said. There's certainly scenarios where it might make sense to decouple the two, but one shouldn't do it just for the sake of doing it. Unless your "profile" is coming from something external already, such as a CRM, or you actually need different profiles for different consuming apps, there's no reason to split. – Chris Pratt Feb 28 '19 at 19:59