Search code examples
asp.net-coreentity-framework-coreasp.net-identityidentityserver4

How to use IdentityServer4 to authenticate local user from local database?


I'm creating SSO solution for multiple existing projects. Most of the applications already use same database, so same users and I use these users in IdentityServer. But there is one app which has its own users DB and login screen. Users from this table are used in one of the tables in this app (FK).

My idea is to leave existing users DB as is. Add a column MasterUserGuid to Users table that will contain "master" user Guid (so the user that IdentityServer uses for authentication) and implement following flow:

  1. User opens the app and is not signed in
  2. User is redirected to IdentityServer and uses global credentials
  3. User is redirected back to the app which gets global user GUID from claims and authenticates local user (with this GUID in the MasterUserGuid column), instead of using global user

The problem is that I don't know how to implement step 3 or if it's even possible/supported in IdentityServer4. At the moment I'm redirected to IdentityServer, am authenticated and redirected back, but then the app tries to use this external user.

While researching I've read that users should be in one table, so maybe this approach is totally wrong and it would be better to remove local users and break FK for mentioned table and do some manual migration of users.

Is the scenario described in the steps I provided possible and sane?


Solution

  • You need to adjust your application to authenticate via IdentityServer first. Remove all the ASP.NET Core Identity logic related to registration, login etc. assuming all of that will be done on IdentityServer side. Then implement the instance of IClaimsTransformation which will either replace your current ClaimsPrincipalor add additional identities to it if needed with the claim values you want (populated from local database). Here is the example:

    public class MyClaimsTransformer : IClaimsTransformation
    {
        public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
        {
            var claims = new List<Claim>();
            claims.Add(new Claim(...)); // put here your claim type and value
    
            var identity = new ClaimsIdentity(claims);
            principal.AddIdentity(identity);
            return principal;
        }
    }
    

    Then register your claims transformer in IOC in Startup.ConfigureServices method:

    services.AddTransient<IClaimsTransformation, MyClaimsTransformer>();