IdentityServer4を使用しており、トークンの作成時にCLIENT
にカスタムのデフォルトクレームを追加しようとしています。これは、以下に示すように、暗黙的なフローとIProfileService
を使用する場合に可能です。
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);
}
}
そして私のスタートアップでは
services.AddIdentityServer()
.AddProfileService<MyProfileService>()
ただし、これはcannot request OpenID scopes in client credentials flow
のように見えるため、client_credentialgranttypeを使用するクライアントでは機能しません。名前が示すようにIprofileserviceは、profileなどのOpenIdスコープが有効なIdentity
リソースで機能することがわかりました。 client_credential付与タイプGetProfileDataAsync
のプロファイルスコープを要求できないため、呼び出されることはありません。
クライアントのみで作業しており、ユーザーはいないため、以下のようにクライアントオブジェクトにクレームを追加せずに、トークンにクレームを挿入する方法が必要です。
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")
}
}
クレームをデータベースのclient_claimsの一部にしたくないので、上記は必要ありません。トークンリクエストでオンザフライで作成する必要があります。私の質問がより明確になったことを願っています。
いくつかの問い合わせで、私はついにこれを行う方法を見つけました。トークンが要求されたときにクライアントにクレームを動的に追加する方法が必要でした。
そのためには、ICustomTokenRequestValidator
を拡張してから、Startup.csに依存性注入を徹底してクラスを含める必要がありました。
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);
}
}
Startup.csでサービスを構成する
services.AddTransient<ICustomTokenRequestValidator, DefaultClientClaimsAdder>();
または、ClientStore
を使用して、クライアントに新しいクレームを追加することもできます。
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);
}
}