IdentityServer4 - 客户端的委托访问令牌
IdentityServer4 - Delegated access tokens for clients
在 IdentityServer4 中,您可以指定一个 extension grand 来为用户启用委托访问令牌,因此如果一个 Web 服务需要在用户请求期间调用另一个 Web 服务,它可以从 IdentityServer 请求一个新的访问令牌具有有效的范围和受众。我的问题是,这笔赠款被认为是“代表交互式用户”使用的,这导致了我的问题:
如果我的客户端调用一个网络服务,而该网络服务需要在请求期间调用另一个网络服务,我该如何创建委托访问令牌?
我试图修改文档中的示例,但扩展 grand 需要来自拥有“sub”声明的用户的令牌,而不是来自不持有“sub”声明的客户端的令牌。
客户端是一个守护程序应用程序,因此它完全自动运行且无需任何用户交互,并使用客户端凭据流进行身份验证。
澄清我的意思:
这里我们看到一个用例,如果有用户:
- 用户访问一个UI
- UI 将用户重定向到身份服务器进行身份验证(使用授权代码流 + PCKE)。 UI 取回访问令牌
- UI 使用访问令牌调用 WebApi A
- WebApi A 需要访问 WebApi B,但访问令牌是针对 WebApi A 的。因此 WebApi A 向 IdentityServer 请求委托访问令牌以访问 WebApi B。
- IdentityServer 提供委托访问令牌。
- 新的访问令牌被传递到 WebApi B。
这里我们看到相同的用例,但没有用户存在,守护进程应用程序做同样的事情:
- 守护程序应用程序使用客户端凭据流对 IdentityServer 进行身份验证并取回访问令牌
- 守护程序应用程序使用访问令牌调用 WebApi A
- WebApi A 需要访问 WebApi B,但访问令牌是针对 WebApi A 的。因此 WebApi A 向 IdentityServer 请求委托访问令牌以访问 WebApi B。
- 如何让 IdentityServer 为客户端提供委托访问令牌?
- 新的访问令牌被传递到 WebApi B。
对于机器到机器(服务到服务)通信,您通常使用客户端凭证授权。这允许服务在没有用户存在的情况下进行通信。用户 ID(主题)通常包含在使用此流程保护的 API 调用中。
看到这个article
WebApi-A 和 WebApi-B 之间的通信可以使用客户端凭据流完成,在这里您不需要传递来自用户的任何访问令牌。相反,您传递 subjectId(userID) 和可选的一些附加声明作为 A 和 B 之间 API 调用的一部分。这种方式更简单,好处是 A-B 可以在没有任何用户参与的情况下进行通信(例如在后台进行工作流风格的交流)。
我找到了问题的解决方案。您可以扩展委托大的给定示例实现并以某种方式扩展它,即为客户颁发委托令牌:
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var oldToken = context.Request.Raw.Get("token");
if (string.IsNullOrEmpty(oldToken))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var result = await _validator.ValidateAccessTokenAsync(oldToken);
if (result.IsError)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var sub = result.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
if (sub != null)
{
// The old token had a user context
context.Result = new GrantValidationResult(sub, GrantType);
}
// The "magic" is the part below
else
{
// The old token had a client context
var client = result.Claims.FirstOrDefault(c => c.Type.Equals("client_id", StringComparison.Ordinal));
if (string.IsNullOrWhiteSpace(client?.Value))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient);
return;
}
context.Request.ClientId = client.Value;
context.Result = new GrantValidationResult(new Dictionary<string, object>());
}
}
在 IdentityServer4 中,您可以指定一个 extension grand 来为用户启用委托访问令牌,因此如果一个 Web 服务需要在用户请求期间调用另一个 Web 服务,它可以从 IdentityServer 请求一个新的访问令牌具有有效的范围和受众。我的问题是,这笔赠款被认为是“代表交互式用户”使用的,这导致了我的问题:
如果我的客户端调用一个网络服务,而该网络服务需要在请求期间调用另一个网络服务,我该如何创建委托访问令牌?
我试图修改文档中的示例,但扩展 grand 需要来自拥有“sub”声明的用户的令牌,而不是来自不持有“sub”声明的客户端的令牌。
客户端是一个守护程序应用程序,因此它完全自动运行且无需任何用户交互,并使用客户端凭据流进行身份验证。
澄清我的意思:
这里我们看到一个用例,如果有用户:
- 用户访问一个UI
- UI 将用户重定向到身份服务器进行身份验证(使用授权代码流 + PCKE)。 UI 取回访问令牌
- UI 使用访问令牌调用 WebApi A
- WebApi A 需要访问 WebApi B,但访问令牌是针对 WebApi A 的。因此 WebApi A 向 IdentityServer 请求委托访问令牌以访问 WebApi B。
- IdentityServer 提供委托访问令牌。
- 新的访问令牌被传递到 WebApi B。
这里我们看到相同的用例,但没有用户存在,守护进程应用程序做同样的事情:
- 守护程序应用程序使用客户端凭据流对 IdentityServer 进行身份验证并取回访问令牌
- 守护程序应用程序使用访问令牌调用 WebApi A
- WebApi A 需要访问 WebApi B,但访问令牌是针对 WebApi A 的。因此 WebApi A 向 IdentityServer 请求委托访问令牌以访问 WebApi B。
- 如何让 IdentityServer 为客户端提供委托访问令牌?
- 新的访问令牌被传递到 WebApi B。
对于机器到机器(服务到服务)通信,您通常使用客户端凭证授权。这允许服务在没有用户存在的情况下进行通信。用户 ID(主题)通常包含在使用此流程保护的 API 调用中。
看到这个article
WebApi-A 和 WebApi-B 之间的通信可以使用客户端凭据流完成,在这里您不需要传递来自用户的任何访问令牌。相反,您传递 subjectId(userID) 和可选的一些附加声明作为 A 和 B 之间 API 调用的一部分。这种方式更简单,好处是 A-B 可以在没有任何用户参与的情况下进行通信(例如在后台进行工作流风格的交流)。
我找到了问题的解决方案。您可以扩展委托大的给定示例实现并以某种方式扩展它,即为客户颁发委托令牌:
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var oldToken = context.Request.Raw.Get("token");
if (string.IsNullOrEmpty(oldToken))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var result = await _validator.ValidateAccessTokenAsync(oldToken);
if (result.IsError)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var sub = result.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
if (sub != null)
{
// The old token had a user context
context.Result = new GrantValidationResult(sub, GrantType);
}
// The "magic" is the part below
else
{
// The old token had a client context
var client = result.Claims.FirstOrDefault(c => c.Type.Equals("client_id", StringComparison.Ordinal));
if (string.IsNullOrWhiteSpace(client?.Value))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient);
return;
}
context.Request.ClientId = client.Value;
context.Result = new GrantValidationResult(new Dictionary<string, object>());
}
}