c# - 当授予类型为 ClientCredentialsFlow 时,MockIdentityServer 客户端声明不包含在访问 token 中

标签 c# mocking integration-testing identityserver4

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

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

而 Controller 方法是:

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

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

       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,
        };

我总是能成功获得 token ,但不幸的是,该 token 不包含我正在测试和正在为其设置策略的声明信息。 以下是调用..

            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.
           }

目前,我收到“未经授权” 请求。因为由于 claim 不可用,它没有通过政策。 任何人都可以告诉我我做错了什么吗?是否有特定的方法来获取所有声明的 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();
    }

最佳答案

我想通了整个故事中的所有问题。

首先在memoy ApiResources中构建时,scopes还应该包含“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 非常感谢您的评论,您指出了构建测试客户端时必需的“id”内容。因为客户声称 alwazs 在通过网络传输到应用程序时会得到前缀。

谢谢

关于c# - 当授予类型为 ClientCredentialsFlow 时,MockIdentityServer 客户端声明不包含在访问 token 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58939442/

相关文章:

c# - 如何用字符串替换控件的名称和方法?

c# - 比较 C# 和 ColdFusion 之间的密码哈希 (CFMX_COMPAT)

java - 模拟 Java 枚举以添加一个值来测试失败案例

java - Amazon Kinesis + 集成测试

ruby - 如何测试 Sidekiq 作业失败?

c# - 你什么时候定义一个类?

c# - WPF - 使用嵌套的 HierarchicalDataTemplate 在 TreeView 中刷新 CollectionView 而不会丢失选择

php - 模拟 SUT 本身

java - 如何在 Java 上使用单元测试来测试与类的私有(private)字段的交互?

grails - 不计算 Spock 集成测试交互