首页 文章

当我的API需要授权令牌时,如何使用Asp.Net Core 2.0的内存中TestServer类进行集成测试?

提问于
浏览
0

我正在使用ASP.NET Core 2.0 Web API,我想使用ASP.NET Core的TestServer类进行一些集成测试 . 我使用xUnit作为我的测试框架,所以我创建了一个TestServerFixture类,它创建了内存中的TestServer实例,然后使用TestServer的.CreateClient()来创建HTTPClient实例 .

我的Web API需要Azure AD中的OAuth2.0访问令牌 . 我在Startup.cs,ConfigureServices方法中使用此代码进行设置:

// Add Azure AD OAUTH2.0 Authentication Services
        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));

在我的控制器中,我在类上有[Authorize]属性 .

因此,对于我的集成测试设置,我在TestServerFixture中有一个方法,它从Azure AD获取有效令牌,并将其添加到我的客户端请求标头中,如下所示;

Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await _testServerFixture.GetAccessToken());

当我调试集成测试时,我可以看到请求确实包含有效的访问令牌,但是当我运行集成测试时,我仍然从API获得401 Unauthorized .

在进行了一些挖掘之后,我发现了几个与TestServer讨论类似问题的资源,但与我所遇到的身份验证而不是授权相关 . 以下是这些资源的链接;

https://medium.com/@zbartl/authentication-and-asp-net-core-integration-testing-using-testserver-15d47b03045a

How do I integration test a ASP 5/Core Web API with [Authorize] Attributes

http://geeklearning.io/how-to-deal-with-identity-when-testing-an-asp-net-core-application/

这些都讨论了使用自定义中间件将claimPrincipal分配给context.user . 由于这是基于身份验证而不是授权,我不确定我是否可以为我的访问令牌做类似的事情 .

我知道在我的API中,我可以访问HTTPContext.User并提取AppId值,这是访问令牌的一部分,因此认证和授权似乎都使用Context.User .

所以,在我为此目的 Build 自己的自定义中间件之前,我想看看是否有人已经解决了这个问题,或者是否知道NuGet能够满足我的需求 .

EDIT - SOLUTION

我正在展示这个以防其他人遇到这个问题 .

我最终构建了Zach Bartlett在他的_1083078中提出的中间件,但做了以下更改 .

public class AuthenticatedTestRequestMiddleware
{

    #region Class Variables

    private const string TestingAccessTokenAuthentication = "TestingAccessTokenAuthentication";
    private readonly RequestDelegate _next;

    #endregion Class Variables

    #region Constructor(s)

    public AuthenticatedTestRequestMiddleware(RequestDelegate next)
    {
        _next = next;
    }


    #endregion Constructor(s)

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Headers.Keys.Contains("X-Integration-Testing"))
        {

            if (context.Request.Headers.Keys.Contains("Authorization"))
            {
                var token = context.Request.Headers["Authorization"].First();

                var claimsIdentity = new ClaimsIdentity(new List<Claim>
                {
                    new Claim(ClaimTypes.Authentication, token)
                }, TestingAccessTokenAuthentication);

                var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
                context.User = claimsPrincipal;
            }
        }

        await _next(context);
    }

}

有一个有趣的“Gotcha” .

在Zach的博客中他有代码;

public const string TestingHeader = "X-Integration-Testing";

在他的中间件的顶部,然后在测试中引用TestingHeader中的 Headers 集合中的键,如下所示;

if (context.Request.Headers.Keys.Contains(TestingHeader)

这样做对我来说是失败的,直到我把字符串文字而不是变量放入.Contains()子句 .

现在,我的集成测试正在通过200 OK响应 . :)

1 回答

  • 0

    我能够找到Zach Bartlett的blog post之后的解决方案,并进行一些小改动以使其与Authentication头相关 . 代码在我上面的原始帖子中显示为编辑 .

相关问题