IdentityServer4: Add Custom default Claim to Clien

2020-03-12 11:59发布

问题:

I am using IdentityServer4 and I am trying to add a custom default claim to my CLIENT when the token is created. This is possible if i use the implicit flow and IProfileService like shown below.

public class MyProfileService : IProfileService
{
    public MyProfileService()
    {

    }
    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var claims = new List<Claim>
        {
            new Claim("DemoClaimType", "DemoClaimValue")
        };
        context.IssuedClaims = claims;
        return Task.FromResult(0);
    }
    public Task IsActiveAsync(IsActiveContext context)
    {
        context.IsActive = true;
        return Task.FromResult(0);
    }
}

And in my startup

services.AddIdentityServer()
            .AddProfileService<MyProfileService>()

However this does not work with my client with client_credential granttype since it seems cannot request OpenID scopes in client credentials flow. It turns out Iprofileservice like the name implies works for Identity Resources where the OpenId scopes like profile is valid. since am unable to request profile scopes with client_credential grant type GetProfileDataAsync never gets called.

Since am working only with clients and no users I need a way to inject claims into the token without having to add them to the client object like below

    new Client
{
    ClientId = "myclient",
    ClientName = "My Client",
    AllowedGrantTypes = GrantTypes.ClientCredentials,
    ClientSecrets = {new Secret("secret".Sha256())},
    AllowedScopes = new List<string> {"api"},                    
    AllowOfflineAccess = true,

    //I Don't want to do this
    Claims = new List<Claim>
    {   
        new Claim("type","value")
    }
}

I do not want the above because i do not want the the claim to be part of the client_claims in the database. I need to create it on the fly on token request. I hope my question is clearer now.

回答1:

With some inquiries I finally found out how to do this. I needed a way to add claims dynamically to the client when token was requested.

In order to do that I had to extend ICustomTokenRequestValidator and then include my class in Startup.cs thorough dependency injection

public class DefaultClientClaimsAdder : ICustomTokenRequestValidator
{
    public Task ValidateAsync(CustomTokenRequestValidationContext context)
    {
        context.Result.ValidatedRequest.Client.AlwaysSendClientClaims = true;
        context.Result.ValidatedRequest.ClientClaims.Add(new Claim("testtoken","testbody"))

        return Task.FromResult(0);
    }
}

Configure services in Startup.cs

 services.AddTransient<ICustomTokenRequestValidator, DefaultClientClaimsAdder>();


回答2:

Alternatively, you can use ClientStore to add new claims into clients.

public class YourClientStore : IClientStore
{
    private readonly DbContext _context;
    private readonly IMapper _mapper;
    public YourClientStore(DbContext context,
        IMapper mapper)
    {
        _context= context;
        _mapper = mapper;
    }

    public Task<Client> FindClientByIdAsync(string clientId)
    {
        var dbClient = _context.Clients.AsQueryable()
            .Where(x => x.ClientId == clientId)
            .FirstOrDefault();
        var client = _mapper.Map<Client>(dbClient);
        if (client != null)
        {
            client.Claims.Add(new Claim("<your claim name>", "<your claim value>"));
        }
        return Task.FromResult(client);
    }
}