You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Ocelot与OpenIddict解析id_token并向微服务传递双令牌声明?

可以解析id_token并合并两个令牌的声明传递给微服务

完全可以实现这个需求,你需要通过以下步骤修改现有配置和代码:

步骤1:确认OpenIddict验证配置(已支持id_token验证)

你当前的OpenIddict配置已经设置了签发者(Issuer)和Discovery相关服务,足以支持id_token的签名验证与有效性校验,无需额外调整这部分代码。

步骤2:在Ocelot中间件中提取、验证并合并声明

修改PreAuthorizationMiddleware逻辑,从请求中获取id_token,验证其有效性后将声明合并到当前用户的ClaimsPrincipal中。假设客户端通过X-Id-Token请求头传递id_token,代码修改如下:

var configuration = new OcelotPipelineConfiguration
{
    PreAuthorizationMiddleware = async (ctx, next) =>
    {
        // 先执行默认授权逻辑,获取access_token对应的声明
        await next.Invoke();

        // 从请求头提取id_token
        if (ctx.Request.Headers.TryGetValue("X-Id-Token", out var idTokenValues) && 
            !string.IsNullOrEmpty(idTokenValues.FirstOrDefault()))
        {
            var idToken = idTokenValues.FirstOrDefault();
            var validationService = ctx.RequestServices.GetRequiredService<IOpenIddictValidationService>();

            try
            {
                // 验证并解析id_token
                var validationResult = await validationService.ValidateTokenAsync(new OpenIddictValidationTokenContext
                {
                    Token = idToken,
                    TokenType = OpenIddictConstants.TokenTypes.IdToken
                });

                if (validationResult.IsValid)
                {
                    // 合并access_token和id_token的声明
                    var currentClaims = ctx.User.Claims.ToList();
                    foreach (var idTokenClaim in validationResult.Principal.Claims)
                    {
                        // 避免重复声明,可根据业务需求调整覆盖逻辑
                        if (!currentClaims.Any(c => c.Type.Equals(idTokenClaim.Type, StringComparison.OrdinalIgnoreCase)))
                        {
                            currentClaims.Add(idTokenClaim);
                        }
                    }

                    // 更新上下文用户信息为合并后的声明集合
                    ctx.User = new ClaimsPrincipal(new ClaimsIdentity(currentClaims, ctx.User.Identity.AuthenticationType));
                }
            }
            catch
            {
                // 处理id_token验证失败的情况,直接返回401
                ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
                await ctx.Response.WriteAsync("无效的ID Token");
                return;
            }
        }
    }
};

步骤3:配置Ocelot传递合并后的声明到下游微服务

修改ocelot.json,通过ClaimsToHeaders将合并后的声明以请求头的形式传递给下游服务,示例配置如下:

{
  "Routes": [
    {
      "UpstreamPathTemplate": "/your-service/{everything}",
      "DownstreamPathTemplate": "/api/{everything}",
      "UpstreamHttpMethod": ["Get", "Post"],
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7001
        }
      ],
      "ClaimsToHeaders": [
        {
          "ClaimType": "sub",
          "HeaderName": "X-User-Id"
        },
        {
          "ClaimType": "name",
          "HeaderName": "X-User-Name"
        },
        // 添加其他需要传递的声明
        {
          "ClaimType": "email",
          "HeaderName": "X-User-Email"
        }
      ]
    }
  ]
}

关键注意事项

  • 安全性:必须通过OpenIddict的验证服务校验id_token的签名、签发者、受众和过期时间,禁止直接解析未验证的id_token。
  • 声明冲突处理:如果access_token和id_token包含同类型的声明,需根据业务需求决定是保留原有值、覆盖还是同时传递。
  • 客户端配合:需要客户端在请求网关时,除了在Authorization头传递access_token外,额外通过自定义头(如X-Id-Token)传递id_token。

内容的提问来源于stack exchange,提问作者Khadija Mehmood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 01:37:01