【问题标题】:MockIdentityServer Client Claims not included in the access token when Grant type was ClientCredentialsFlow当授予类型为 ClientCredentialsFlow 时,访问令牌中不包含 MockIdentityServer 客户端声明
【发布时间】:2019-11-19 17:09:53
【问题描述】:

我有受政策保护的 API 控制器。此策略在 Startup.cs 中配置,如

 options.AddPolicy("InternalClient", policy =>
                policy.RequireAssertion(context =>
                    context.User.HasClaim(c =>                           
                         (c.Type == "client_id" && c.Value == "installation-logic-client-id"))));

而控制器方法是:

    [HttpGet("{familyId}/versions/{version}/infos")]
    [Authorize(Policy = "InternalClient")]     
    public IActionResult GetTestInfo(Guid testFamilyId, string version)
    {
        ..............................
    }

并测试上述方法,我从 MockIdentityServer 获取令牌。在那里我正在配置客户端

       yield return new Client
        {
            ClientId = "installation-logic-client-id",
            ClientSecrets = new[] {new Secret("installation-logic-client-secret".Sha256())},
            AllowedGrantTypes = GrantTypes.ClientCredentials,
            AllowedScopes = new[] {"installation-logic-scope"},
            AllowOfflineAccess = true,
            AccessTokenType = AccessTokenType.Jwt,
            RefreshTokenUsage = TokenUsage.OneTimeOnly,
            RefreshTokenExpiration = TokenExpiration.Sliding,

            Claims = new List<Claim>() // I want these claims to  be added in the access_token so that they can be verified while making the request.
            {
                new Claim("client_id", "installation-logic-client-id")
            },
            AlwaysSendClientClaims = true,
            AlwaysIncludeUserClaimsInIdToken = true,
        };

我总是成功获得令牌,但不幸的是,该令牌不包含我正在测试的声明信息以及正在为其设置的策略。 以下是电话..

            private async Task<string> GetTokenForInternalClient()
            {
               var tokenRequest = new ClientCredentialsTokenRequest() 
               {
                  Address = await GetTokenEndpoint(),
                  ClientId = MockConstants.TokenInstallationLogicClientId,
                  ClientSecret = MockConstants.TokenInstallationLogicClientSecret,
                  Scope = MockConstants.TokenInstallationLogicScope
               };

             var tokenResponse = await 
             _identityServerClient.RequestClientCredentialsTokenAsync(tokenRequest);
              if (tokenResponse.IsError) throw new MockIdentityServerException(tokenResponse);

             return tokenResponse.AccessToken; // Here I see very short token. Clearly it doesn't contains the claims.
           }

目前,我收到 'Unauthorized' 请求。因为由于索赔不可用,它没有通过政策。 任何人都可以告诉我我做错了什么吗?是否有特定的方法来获取所有声明的 access_token

在 Client 对象中将 client_id 更改为策略级别的 id 后,还将 TokenType 更改为 'Jwt' 而不是 opf Reference,我得到了以下 Payload。

    {
  "nbf": 1574191641,
  "exp": 1574195241,
  "iss": "http://localhost:5000",
  "aud": "installation-logic-scope",
  "client_id": "installation-logic-client-id",
  "scope": [
    "installation-logic-scope"
  ]
}

更新的声明(有效负载正文)

{
  "nbf": 1574198669,
  "exp": 1574202269,
  "iss": "http://localhost:5000",
  "aud": "installation-logic-client-id",
  "client_id": "installation-logic-client-id",
  "scope": [
    "installation-logic-scope"
  ]
}

Startup.cs

private static void ConfigureAuthorization(IServiceCollection services)
    {
        services.AddAuthorization(options =>
        {
            options.AddPolicy("admin", pb => pb.RequireClaim("Role", "admin", "orgadmin"));
            options.AddPolicy("InternalClient", policy =>
                policy.RequireAssertion(context =>
                    context.User.HasClaim(c =>
                        ((c.Type == "Role" && (c.Value == "admin" || c.Value == "orgadmin")) ||
                         (c.Type == "id" && c.Value == "installation-logic-client-id")))));
        });
    }

    private void ConfigureDbContexts(IServiceCollection services)
    {
             ........................            
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    [UsedImplicitly]
    public void Configure(IApplicationBuilder app, PackageHandlingContext dbContext)
    {           
        // middlewares: order is important
        app.UseRouting();
        app.UseCors("AnyOrigin");
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseHttpsRedirection();

        app.UseEndpoints(endpoints => endpoints.MapControllers());

        dbContext.Database.EnsureCreated();
    }

【问题讨论】:

  • 编辑并显示了有效载荷。
  • 用 Startup.cs 更新了问题
  • 我刚刚更正了 ApiScope 并使用了您的建议。在构建客户端时,我使用的是“id”。在此之后,它开始在令牌内返回正确的 clims。所以我收到了 7 个声明,通过反省,我也验证了这一点。但是在提出请求时我仍然未经授权,因为配置的策略在某种程度上无法被这些声明识别
  • 获得了更新的声明。 { “nbf”:1574198669,“exp”:1574202269,“iss”:“localhost:5000”,“aud”:“安装逻辑客户端 ID”,“客户端 ID”:“安装逻辑客户端 ID” , "范围": [ "安装逻辑范围" ] }

标签: c# mocking integration-testing identityserver4


【解决方案1】:

我发现了整个故事中的所有问题。

首先在 memoy ApiResources 中构建时,范围还应该包含“client_id”。

Scopes = new List<Scope>
{
   new Scope(MockConstants.PackageHandlingScope, new[] {"Role", "client_id"})
},

其次,构建测试客户端,只需要使用"id"作为声明类型,因为client_已经以声明类型为前缀。

更新的客户端将是

yield return new Client
        {
            ClientId = MockConstants.TokenInstallationLogicClientId,
            ClientSecrets = new[] {new Secret(MockConstants.TokenInstallationLogicClientSecret.Sha256())},
            AllowedGrantTypes = GrantTypes.ClientCredentials,
            AllowedScopes = new[] {MockConstants.PackageHandlingScope},
            AllowOfflineAccess = true,
            AccessTokenType = AccessTokenType.Jwt,
            RefreshTokenUsage = TokenUsage.OneTimeOnly,
            RefreshTokenExpiration = TokenExpiration.Sliding,

            Claims = new List<Claim>
            {
                new Claim("id", "installation-logic-client-id")
            }
        };

其他都还好。

@Ruard van Elburg 非常感谢您的 cmets,您指出了构建测试客户端时需要的“id”内容。因为客户端声称在通过网络传输到应用程序时会添加前缀。

谢谢

【讨论】:

  • prefix(向下滚动到ClientClaimsPrefix),如文档所述:如果设置,前缀客户端声明类型将以前缀为前缀。默认为client_。目的是确保它们不会意外地与用户声明发生冲突。
猜你喜欢
  • 2023-01-11
  • 1970-01-01
  • 1970-01-01
  • 2019-06-21
  • 2021-07-25
  • 2016-10-16
  • 2020-02-25
  • 2017-03-23
  • 2021-03-19
相关资源
最近更新 更多