更新:更正了证书问题之后,我现在从测试中获得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:承载错误=“ 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);
在不是我进行的xunit测试的上下文中运行时,是否需要解决一些问题?
答案 0 :(得分:0)
我想出的唯一解决方案是在API项目的Startup类上设置一个静态Handler,然后在每个单元测试中覆盖它。
特别是:
// 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