【问题标题】:How can I set my IdentityServer4 BackChannelHandler from within an xUnit integration test using WebApplicationFactory?如何使用 WebApplicationFactory 从 xUnit 集成测试中设置我的 IdentityServer4 BackChannelHandler?
【发布时间】:2019-03-27 23:14:01
【问题描述】:

更新:更正证书问题后,我现在在测试中收到 500 响应,其中包含以下消息:

InvalidOperationException:IDX20803:无法从“http://localhost/.well-known/openid-configuration”获取配置。

这似乎与这个问题相似:https://github.com/IdentityServer/IdentityServer4/issues/685;但是,我无法从我的测试中想出一种方法来设置反向通道客户端或处理程序——这似乎是先有鸡还是先有蛋的情况。


已通过使用真实证书/.pfx 文件解决了此问题。这导致了上述问题。

我正在使用WebApplicationFactory 对我的 API 进行集成测试,并且我认为我已经涵盖了正确配置 http 客户端的所有基础。在我的 API 中调用操作时出现错误。

这是使用令牌对 api 执行 get 时的错误:

WWW-Authenticate: Bearer error="invalid_token", error_description="找不到签名密钥"

这是一个演示这个问题的简单测试类:

public class EntityControllerShould : IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly WebApplicationFactory<Startup> _factory;

    public EntityControllerShould(WebApplicationFactory<Startup> factory)
    {
        _factory = factory;
    }

    [Fact]
    public async Task ReturnListOfEntities_ForGet()
    {
        // arrange
        _factory.CreateClient();

        var handler = _factory.Server.CreateHandler();

        var client = new HttpClient(handler) { BaseAddress = new System.Uri("http://localhost/") };

        // discover endpoints from metadata
        var dc = new DiscoveryClient(client.BaseAddress.ToString(), handler);
        var disco = await dc.GetAsync();
        if (disco.IsError)
        {
            Assert.True(false);
        }
        // request token
        var tokenClient = new TokenClient(disco.TokenEndpoint, "api_client", "secret", handler);
        var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");

        if (tokenResponse.IsError)
        {
            Assert.True(false);
        }

        client.SetBearerToken(tokenResponse.AccessToken);

        // act
        var response = await client.GetAsync("api/entity/?id=123");
        // response code is 401 with the above quoted error in the header
        response.EnsureSuccessStatusCode();

        var responseString = await response.Content.ReadAsStringAsync();

        // assert
        Assert.NotNull(responseString);
    }
}

从 API 项目中的 Startup.cs 截取:

services.AddIdentityServer()
            .AddSigningCredential(myCertificate)
            .AddSigningCredential()
            .AddClientStore<CustomClientStore>()
            .AddInMemoryIdentityResources(IdentityServerConfig.IdentityResources)
            .AddInMemoryApiResources(IdentityServerConfig.Apis);
  • 我将 IdentityServer4 和 API 托管在同一个项目中。
  • 当我通过浏览器手动执行集成测试时,它工作得很好
  • 我找到了this which seems very similar

在我不是 xunit 测试的上下文中运行时我需要考虑什么?

【问题讨论】:

    标签: c# .net oauth identityserver4 openid-connect


    【解决方案1】:

    我想出的唯一解决方案是在 API 项目的 Startup 类上设置一个静态处理程序,然后在每个单元测试中覆盖它。

    具体来说:

    // startup.cs
    public static HttpMessageHandler Handler { get; set; }
    
    // snip from configureservices
    .AddJwtBearer(jwt =>
     {
          // defaults as they were
          jwt.Authority = "http://localhost:5000/";
          jwt.RequireHttpsMetadata = false;
          jwt.Audience = "api1";
          // if static handler is null don't change anything, otherwise assume integration test.
          if(Handler == null)
          {
              jwt.BackchannelHttpHandler = Handler;
              jwt.Authority = "http://localhost/";
          }
      });
    

    IdSvrAndApi 项目的完整列表:

     public class Startup
     {
         public Startup(IConfiguration configuration)
         {
             Configuration = configuration;
         }
    
         public IConfiguration Configuration { get; }
         public static HttpMessageHandler Handler { get; set; }
    
         public void ConfigureServices(IServiceCollection services)
         {
             services.AddMvc();
    
             services.AddIdentityServer()
                 .AddDeveloperSigningCredential()
                 .AddInMemoryIdentityResources(Config.IdentityResources)
                 .AddInMemoryClients(Config.Clients)
                 .AddInMemoryApiResources(Config.Apis)
                 .AddTestUsers(TestUsers.Users);
    
            services.AddAuthentication()
               .AddJwtBearer(jwt =>
               {
                   jwt.BackchannelHttpHandler = Handler;
                   jwt.Authority = "http://localhost/";
                   jwt.RequireHttpsMetadata = false;
                   jwt.Audience = "api1";
               });
                .AddJwtBearer(jwt =>
                {
                    // defaults as they were
                    jwt.Authority = "http://localhost:5000/";
                    jwt.RequireHttpsMetadata = false;
                    jwt.Audience = "api1";
                    // if static handler is null don't change anything, otherwise assume integration test.
                    if(Handler == null)
                    {
                        jwt.BackchannelHttpHandler = Handler;
                        jwt.Authority = "http://localhost/";
                    }
                });
        }
    

    可以在此处查看完整的工作示例:https://github.com/fuzzzerd/IdentityServerAndApi

    我还没有收到关于这是否是实现此目标的推荐方法的明确答案,但我确实在这里打开了一个关于该项目的问题:https://github.com/IdentityServer/IdentityServer4/issues/2877

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-19
      • 2022-06-16
      • 2019-07-23
      • 1970-01-01
      • 2017-10-04
      • 2019-03-15
      • 2023-03-18
      • 2018-05-08
      相关资源
      最近更新 更多