1

我在asp.net core 1.1项目中实现Aspnet OpenIdConnect Server (ASOS),我目前正在尝试使用 Microsoft.AspNetCore.TestHost.TestServer实现一些集成测试 ( & )。xunitmoq

我遇到的问题是手动生成一个伪造的访问令牌来填充AuthenticationHeaderValue请求HttpClient。寻找一个可行的解决方案,但到目前为止我没有成功。

所以我的问题是:任何人都知道如何为 TestServer 手动生成访问令牌,而无需调用 ASOS 的令牌端点进行测试?

4

1 回答 1

1

虽然 ASOS 故意阻止您从任意位置创建令牌(它们只能在 OpenID Connect 请求期间生成),但您可以直接使用底层 ASP.NET Core API 生成将被 OAuth2 验证中间件接受的假令牌:

var provider = container.GetRequiredService<IDataProtectionProvider>();
var protector = provider.CreateProtector(
    nameof(OpenIdConnectServerMiddleware),
    OpenIdConnectServerDefaults.AuthenticationScheme, "Access_Token", "v1");

var format = new TicketDataFormat(protector);

var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.Name, "Bob le Bricoleur"));

var ticket = new AuthenticationTicket(
    new ClaimsPrincipal(identity),
    new AuthenticationProperties(),
    OpenIdConnectServerDefaults.AuthenticationScheme);

var token = format.Protect(ticket);

也就是说,如果您想测试自己的受令牌保护的 API,这很少是最有效的方法。相反,我建议设置HttpContext.User或使用 OAuth2 验证中间件事件来使用假身份而不涉及加密操作。

您还可以模拟AccessTokenFormat

[Fact]
public async Task ValidTokenAllowsSuccessfulAuthentication()
{
    // Arrange
    var server = CreateResourceServer();

    var client = server.CreateClient();

    var request = new HttpRequestMessage(HttpMethod.Get, "/");
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "valid-token");

    // Act
    var response = await client.SendAsync(request);

    // Assert
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    Assert.Equal("Fabrikam", await response.Content.ReadAsStringAsync());
}


private static TestServer CreateResourceServer(Action<OAuthValidationOptions> configuration = null)
{
    var builder = new WebHostBuilder();

    var format = new Mock<ISecureDataFormat<AuthenticationTicket>>(MockBehavior.Strict);

    format.Setup(mock => mock.Unprotect(It.Is<string>(token => token == "invalid-token")))
          .Returns(value: null);

    format.Setup(mock => mock.Unprotect(It.Is<string>(token => token == "valid-token")))
          .Returns(delegate
          {
              var identity = new ClaimsIdentity(OAuthValidationDefaults.AuthenticationScheme);
              identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "Fabrikam"));

              var properties = new AuthenticationProperties();

              return new AuthenticationTicket(new ClaimsPrincipal(identity),
                  properties, OAuthValidationDefaults.AuthenticationScheme);
          });

    builder.ConfigureServices(services =>
    {
        services.AddAuthentication();
    });

    builder.Configure(app =>
    {
        app.UseOAuthValidation(options =>
        {
            options.AccessTokenFormat = format.Object;

            // Run the configuration delegate
            // registered by the unit tests.
            configuration?.Invoke(options);
        });

        // Add the middleware you want to test here.

        app.Run(context =>
        {
            if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
            {
                return context.Authentication.ChallengeAsync();
            }

            var identifier = context.User.FindFirst(ClaimTypes.NameIdentifier).Value;
            return context.Response.WriteAsync(identifier);
        });
    });

    return new TestServer(builder);
}
于 2016-12-16T20:38:34.107 回答