带有 ClientCredentials 流的 OpenIdDict 降级模式
Posted
技术标签:
【中文标题】带有 ClientCredentials 流的 OpenIdDict 降级模式【英文标题】:OpenIdDict Degraded Mode with ClientCredentials flow 【发布时间】:2021-09-27 19:53:07 【问题描述】:我正在关注这篇关于允许 OpenIDDict 包装替代身份验证提供程序但从 OpenIDDict 本身返回 JWT 令牌的博客:
https://kevinchalet.com/2020/02/18/creating-an-openid-connect-server-proxy-with-openiddict-3-0-s-degraded-mode/
这实际上是关于拦截授权代码流而不是客户端凭据流,但它提供了一个很好的起点。
不幸的是,它声明“我们不需要覆盖 HandleTokenRequestContext”,这适用于博客,但不适合(据我所知)我的用例。
我想我需要实现一个自定义 HandleTokenRequestContext 但是当我这样做时,代码运行,没有错误但 HTTP 响应为空。没有生成令牌。
我应该如何正确拦截客户端凭据流,以便我可以调用另一个提供商来验证凭据、获取结果并将其包含在我需要添加到 JWT 的自定义声明中?
代码如下:
public void ConfigureServices(IServiceCollection services)
services.AddDbContext<DbContext>(options =>
// Configure the context to use an in-memory store - probably not needed?
options.UseInMemoryDatabase(nameof(DbContext));
// Register the entity sets needed by OpenIddict.
options.UseOpenIddict();
);
services.AddOpenIddict()
.AddCore(options =>
options.UseEntityFrameworkCore()
.UseDbContext<DbContext>();
)
.AddServer(options =>
options.SetTokenEndpointUris("/connect/token");
options
//.AllowRefreshTokenFlow()
.AllowClientCredentialsFlow();
// Register the signing and encryption credentials.
// options.AddDevelopmentEncryptionCertificate()
// .AddDevelopmentSigningCertificate();
//Development only
options
.AddEphemeralEncryptionKey()
.AddEphemeralSigningKey()
.DisableAccessTokenEncryption();
// Register scopes (i.e. the modes we can operate in - there may be a better way to do this (different endpoints?)
options.RegisterScopes("normal", "registration");
//TODO: Include Quartz for cleaning up old tokens
options.UseAspNetCore()
.EnableTokenEndpointPassthrough();
options.EnableDegradedMode(); //Activates our custom handlers as the only authentication mechansim, otherwise the workflow attempt to invoke our handler *after* the default ones have already failed
//the request
options.AddEventHandler<ValidateTokenRequestContext>(builder =>
builder.UseInlineHandler(context =>
//TODO: Check that the client Id is known
if (!string.Equals(context.ClientId, "client-1", StringComparison.Ordinal))
context.Reject(
error: Errors.InvalidClient,
description: "The specified 'client_id' doesn't match a known Client ID.");
return default;
return default;
));
options.AddEventHandler<HandleTokenRequestContext>(builder =>
builder.UseInlineHandler(context =>
var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, OpenIddictConstants.Claims.Name, OpenIddictConstants.Claims.Role);
identity.AddClaim(OpenIddictConstants.Claims.Subject, context.ClientId, OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken);
if (context.Request.Scope == "registration")
//TODO: Authenticate against BackOffice system to get it's token so we can add it as a claim
identity.AddClaim("backoffice_token", Guid.NewGuid().ToString(), OpenIddictConstants.Destinations.AccessToken);
else
//TODO: Authenticate against internal authentication database as normal
var cp = new ClaimsPrincipal(identity);
cp.SetScopes(context.Request.GetScopes());
context.Principal = cp;
//This doesn't work either
//context.SignIn(context.Principal);
//ERROR: When this exits the response is empty
return default;
));
);
//.AddValidation(options =>
//
// options.UseLocalServer();
// options.UseAspNetCore();
//);
services.AddControllers();
services.AddHostedService<CredentialLoader>();
【问题讨论】:
【参考方案1】:最后,我做了 3 处改动:
在 HandleTokenRequestContext 中:
var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType);
不确定这是否必要。然后删除
context.Principal = cp;
但重新添加
context.SignIn(context.Principal);
【讨论】:
以上是关于带有 ClientCredentials 流的 OpenIdDict 降级模式的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Delphi XE 发送 WCF 的 ClientCredentials
在 App.config 中设置 WCF ClientCredentials
使用自定义 ClientCredentials 进行 WCF 身份验证:要使用的 clientCredentialType 是啥?
无法将 @LoadBalanced 与在 ClientCredentials 上配置的 OAuth2RestTemplate 一起使用