如何在使用OpenIddict请求令牌时添加自定义声明?

4

我正在构建一个跨平台的ASP.NET Core 1.1应用程序,并尝试(使用此示例)在请求/connect/token端点时向返回的access_token添加自定义声明。
我需要的不仅是将声明序列化到access_token中返回,还需要将它们像这样在响应中返回:

{
 "token_type": "Bearer",
 "access_token": "...",
 "expires_in": 1799,
 "custom_claim": "..."
}

我在互联网上发现我必须使用 AspNet.Security.OpenIdConnect.Server 并编写我的提供程序才能做我想做的事情。
难道没有使用第一个示例的简单方法吗?
我正在使用OAUth 2.0,授权类型为 Password,不使用JWT。
不是不使用JWT的要求,只是我曾经在ASP.NET 4.5中使用过OAuth。

你需要以那种格式吗?即使在Javascript中,反序列化返回令牌的有效负载部分也非常简单。只是好奇你为什么想要像你的示例那样。 - Louis Lewis
@LouisLewis 我没有使用JWT,所以我认为反序列化不适用,即使我使用JWT,我也无法返回令牌中的自定义声明。 - Dabbas
3个回答

5
我需要的不仅仅是返回access_token中序列化的声明,也需要像这样在响应中返回它们:
我鼓励你将这些声明存储在身份令牌中 - 这样客户端可以完全标准的方式轻松读取它们,但在OpenIddict 1.0和2.0 RTM中有可能。为此,你有两个选择:
使用特殊的“public”属性(在授权控制器中,创建身份验证票证时):
ticket.SetProperty("custom_claim" + OpenIddictConstants.PropertyTypes.String, user.Id);

注意:OpenIddictConstants.PropertyTypes.String是一个特殊后缀,表示添加到票证的身份验证属性可以作为令牌响应的一部分公开。如果您更喜欢将声明作为JSON数字或更复杂的JSON结构返回,则可以使用其他常量。
使用事件模型(在Startup.cs中):
services.AddOpenIddict()

    // Register the OpenIddict core services.
    .AddCore(options =>
    {
        // ...
    })

    // Register the OpenIddict server handler.
    .AddServer(options =>
    {
        // ...

        options.AddEventHandler<OpenIddictServerEvents.ApplyTokenResponse>(
            notification =>
            {
                if (string.IsNullOrEmpty(notification.Context.Error))
                {
                    var principal = notification.Context.Ticket.Principal;
                    var response = notification.Context.Response;
                    response["custom_claim"] = principal.FindFirst("your_claim_attached_to_the_principal").Value;
                }

                return Task.FromResult(OpenIddictServerEventState.Unhandled);
            });
    })

    // Register the OpenIddict validation handler.
    .AddValidation();

你好Kevin,我是oppniddict的新手,在最新版本3.0.1中,这段代码已经过时了,你能否请教一下我们如何在当前版本中传递自定义声明?我尝试了以下代码但不起作用:options.AddEventHandler<ApplyTokenResponseContext>(builder => { builder.UseInlineHandler(context => { if (string.IsNullOrEmpty(context.Error)) { var principal = context.Principal; var response = context.Response; response.AddParameter("custom_claim", "test"); } return default; }); });客户端应用程序没有收到自定义声明。 - user2507201
@user2507201 你好。你的代码看起来很好,应该可以正常工作(在我的电脑上也是这样)。不确定出了什么问题。 - Kévin Chalet
你说得对,它完美地运行了,是我的错误。谢谢。 - user2507201

2

我们是通过在添加 Open Id Connect 中间件时,在 Startup 类的 Configure 方法中使用 OpenIdConnectOptionsEvents 属性来实现的,例如:

            Events = new OpenIdConnectEvents
            {
                OnTicketReceived = n =>
                {
                    //TODO Your logic here to add custom claims via n.Principal.Identities.First().AddClaims();

                    return Task.CompletedTask;
                }
            }

这是否适用于您的使用情况?


0

作为 @Pinpoint 在他的 openiddict-samples 存储库中的答案,我遵循了 这篇文章(在 实现 Connect/Token 端点 部分)...
从他的回答中我发现我尝试做的不是标准的,这就是为什么它不那么明显和容易的原因。
你需要使用 JWT 并将自定义声明添加到其中,以便客户端可以解码它并获取声明,而不是通过响应本身发送它们。


1
注意:如果您只想在授权服务器和客户端应用程序之间共享声明,请不要使用JWT作为访问令牌格式。相反,将OpenIdConnectConstants.Destinations.IdentityToken目标附加到您的声明中,并添加scope=openid以检索身份令牌(根据定义必须是JWT),您将能够内省以检索所需的声明。 - Kévin Chalet
@Pinpoint 我想要返回 access_token 和它的声明。 - Dabbas
身份标识令牌是单独的令牌(id_token)。 - Kévin Chalet
@Pinpoint 抱歉,我不是JWT和OAuth方面的专家,但使用JWT有什么问题吗? - Dabbas
1
没有什么问题。问题在于尝试从客户端代码中读取访问令牌(这是不应该做的,因为它不是令牌的预期受众)。 - Kévin Chalet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接