Search code examples
asp.netasp.net-coreidentityserver4

Set Claim after login using IdentityServer in different software


I have two software and would like to integrate to a single identityserver. both are software is multi tenant, using shared database

All tables have a column named TenantId and in my DbContext (EF Core) I filter Where(x => x.TenantId == TenantId). Currently I store this TenantId in claim and use a simple solution to generate JWT

In google searches, I have seen that one way to add claim in the access_token is through the ProfileService, but my problem is that in each software the user may have different TenantId

In this question they are using OnTokenValidated to add new Claims

But I wonder, who returns the acess_token for the software? The API or IdentityServer because in this case you need to be the API to add the new Claims

Summary: I want the identityserver only to login and generate token, authorization and other logics will be directly in each of the softwares


Solution

  • In the link that you've added you can see that the access_token actually isn't modified. What happens is that the claims from the access_token are mapped to the User.Identity. And in OnTokenValidated additional claims are added to this User.Identity.

    The problem is that tenantid doesn't fit as claim because IdentityClaims are supposed to model the Identity, which are independent of the context, while something as tenantid's is context dependend.

    For the resource you can't use OnTokenValidated. Instead use middleware. I suggest you take a look at the solution from the IdentityServer team: the PolicyServer.

    In short, after authentication (IdentityServer) the policyserver adds claims to the User.Identity based on the configured authorization.

    There are two parts in the API (=resource):

    1. Extend the User.Identity with authorization claims
    2. Policies, as this where the logic should take place.

    And then you'll have what you want. Resource based authorization.

    The PolicyServer uses a json settings file, but you can extend this with your own store. The example is missing normal claims, but you can extend the Policy model with claims:

    // Just the lines to include claims.
    public class Policy
    {
        public List<Claim> Claims { get; internal set; } = new List<Claim>();
    
        internal Task<PolicyResult> EvaluateAsync(ClaimsPrincipal user)
        {
            var claims = Claims.Select(x => new Claim { Name = x.Name, Value = x.Value }).ToArray();
    
            var result = new PolicyResult()
            {
                Claims = claims
            };
        }
    }
    

    And in the configuration:

    "Policy": {
      "claims": [
        {
          "name": "tenantid",
          "value": "44"
        }
      ],
      "roles": [
    

    In the middleware add the claims to the User.Identity, e.g.:

    id.AddClaims(claims);