我正在使用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讨论类似问题的资源,但与我所遇到的身份验证而不是授权相关 . 以下是这些资源的链接;
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 回答
我能够找到Zach Bartlett的blog post之后的解决方案,并进行一些小改动以使其与Authentication头相关 . 代码在我上面的原始帖子中显示为编辑 .