将 IdentityServer4 与 WebApplicationFactory 集成测试结合使用
Using IdentityServer4 with WebApplicationFactory Integration Tests
我正在尝试让我的集成测试针对受保护的 api 端点进行工作。
我的测试调用 IDS connect/token 端点并获得有效令牌。当我用它来调用受保护的 api 时,我总是会遇到 invalid_token 的失败。 (api 对于 IDS 也是本地的)
如果我手动调试 IDS 并使用 postman 获取令牌,然后手动设置它并使用 postman 调用受保护的 api 它工作正常。
我怀疑 IDS 验证代码的内部无法访问发现端点,因为它正在启动自己的 HttpClient。我知道WebApplicationFactory Client是HttpClient的一个特殊实现。
有没有一种方法可以在 configuration/startup 期间将 WebApplicationFactory 客户端注入 IDS 以使其正常工作?
或者有没有一种方法可以制作一个伪造的授权端点,它只验证 Auth header 中发送的任何令牌?
我只是希望我的集成测试能够针对 api,如果它真的验证了令牌就太好了,但如果不能,我可以伪造它。
谢谢。
以通常的方式,在我问了一些我被难住了几个小时的事情之后,我就想通了。这是基于另一个问题的简单解决方案,它的答案有点复杂 (How can I set my IdentityServer4 BackChannelHandler from within an xUnit integration test using WebApplicationFactory?)。
在你的 Startup.cs 中添加静态 属性:
/// <summary>
/// For integrationtesting set this to Factory.Server.CreateHandler()
/// </summary>
public static HttpMessageHandler JwtBackChannelHandler { get; set; }
然后将此添加到您的 .AddIdentityServerAuthentication()
选项中:
if (JwtBackChannelHandler != null)
{
options.JwtBackChannelHandler = JwtBackChannelHandler;
}
在实现 IClassFixture<WebApplicationFactory<Startup>>
的测试 class 的构造函数中添加:
Startup.JwtBackChannelHandler = Factory.Server.CreateHandler();
这将允许您调用令牌端点并接收真实令牌,并在您的集成测试中将其用作身份验证 header。火爆的数字。
这个答案是针对@liqSTAR 的,关于如何在集成测试中忽略 IdentitiyServer 4 和伪造授权。
创建如下所示的 class:
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var context = Context;
List<Claim> claims;
if (context.Request.Headers.Keys.Contains("my-name"))
{
var name = context.Request.Headers["my-name"].First();
var id = context.Request.Headers.Keys.Contains("my-id") ? context.Request.Headers["my-id"].First() : "";
claims = new List<Claim>
{
new Claim(ClaimTypes.Name, name),
new Claim(ClaimTypes.NameIdentifier, id),
};
}
else
{
claims = new List<Claim> { new Claim(ClaimTypes.Name, "Test user") };
}
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
context.User = principal;
var ticket = new AuthenticationTicket(principal, "Test");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
然后在继承自 WebApplicationFactory<TStartup>
的自定义 class 中添加 override void ConfigureWebHost(IWebHostBuilder builder)
添加
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => {});
转到 builder.ConfigureServices(services => {
部分。
然后在你的测试中class添加
Client.DefaultRequestHeaders.Add("my-id", "1234");
Client.DefaultRequestHeaders.Add("my-name", "Test_User");
当你想模拟一个用户时,你的 ctor 或测试方法,这样 Authorize
属性在你的控制器试图用 User
做某事时起作用。 (Client
方便 属性 我有 Factory.CreateClient();
)
这样做的好处是,如果您不想通过授权用户,请不要设置 my-id 和 my-name headers.
我希望这能帮助您朝着正确的方向前进。
我正在尝试让我的集成测试针对受保护的 api 端点进行工作。 我的测试调用 IDS connect/token 端点并获得有效令牌。当我用它来调用受保护的 api 时,我总是会遇到 invalid_token 的失败。 (api 对于 IDS 也是本地的)
如果我手动调试 IDS 并使用 postman 获取令牌,然后手动设置它并使用 postman 调用受保护的 api 它工作正常。
我怀疑 IDS 验证代码的内部无法访问发现端点,因为它正在启动自己的 HttpClient。我知道WebApplicationFactory Client是HttpClient的一个特殊实现。
有没有一种方法可以在 configuration/startup 期间将 WebApplicationFactory 客户端注入 IDS 以使其正常工作?
或者有没有一种方法可以制作一个伪造的授权端点,它只验证 Auth header 中发送的任何令牌?
我只是希望我的集成测试能够针对 api,如果它真的验证了令牌就太好了,但如果不能,我可以伪造它。
谢谢。
以通常的方式,在我问了一些我被难住了几个小时的事情之后,我就想通了。这是基于另一个问题的简单解决方案,它的答案有点复杂 (How can I set my IdentityServer4 BackChannelHandler from within an xUnit integration test using WebApplicationFactory?)。
在你的 Startup.cs 中添加静态 属性:
/// <summary>
/// For integrationtesting set this to Factory.Server.CreateHandler()
/// </summary>
public static HttpMessageHandler JwtBackChannelHandler { get; set; }
然后将此添加到您的 .AddIdentityServerAuthentication()
选项中:
if (JwtBackChannelHandler != null)
{
options.JwtBackChannelHandler = JwtBackChannelHandler;
}
在实现 IClassFixture<WebApplicationFactory<Startup>>
的测试 class 的构造函数中添加:
Startup.JwtBackChannelHandler = Factory.Server.CreateHandler();
这将允许您调用令牌端点并接收真实令牌,并在您的集成测试中将其用作身份验证 header。火爆的数字。
这个答案是针对@liqSTAR 的,关于如何在集成测试中忽略 IdentitiyServer 4 和伪造授权。
创建如下所示的 class:
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var context = Context;
List<Claim> claims;
if (context.Request.Headers.Keys.Contains("my-name"))
{
var name = context.Request.Headers["my-name"].First();
var id = context.Request.Headers.Keys.Contains("my-id") ? context.Request.Headers["my-id"].First() : "";
claims = new List<Claim>
{
new Claim(ClaimTypes.Name, name),
new Claim(ClaimTypes.NameIdentifier, id),
};
}
else
{
claims = new List<Claim> { new Claim(ClaimTypes.Name, "Test user") };
}
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
context.User = principal;
var ticket = new AuthenticationTicket(principal, "Test");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
然后在继承自 WebApplicationFactory<TStartup>
的自定义 class 中添加 override void ConfigureWebHost(IWebHostBuilder builder)
添加
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => {});
转到 builder.ConfigureServices(services => {
部分。
然后在你的测试中class添加
Client.DefaultRequestHeaders.Add("my-id", "1234");
Client.DefaultRequestHeaders.Add("my-name", "Test_User");
当你想模拟一个用户时,你的 ctor 或测试方法,这样 Authorize
属性在你的控制器试图用 User
做某事时起作用。 (Client
方便 属性 我有 Factory.CreateClient();
)
这样做的好处是,如果您不想通过授权用户,请不要设置 my-id 和 my-name headers.
我希望这能帮助您朝着正确的方向前进。