Я работаю над веб-API ASP.NET Core 2.0 и хочу провести некоторые интеграционные тесты с использованием класса TestServer в ASP.NET Core.Я использую xUnit в качестве своей среды тестирования, поэтому я создал класс TestServerFixture, который создает экземпляр TestServer в памяти, а затем использует .CreateClient () TestServer для создания экземпляра HTTPClient.
Для моего веб-API требуется токен доступа OAuth2.0 из моей Azure AD.Я настроил это с помощью этого кода в моем Startup.cs, метод ConfigureServices:
// Add Azure AD OAUTH2.0 Authentication Services
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));
, и в моих контроллерах у меня есть атрибут [Authorize] для класса.
Итак, для моей настройки Integration Tests у меня есть метод в моей TestServerFixture, который получает действительный токен из Azure AD, и я добавляю его в мой заголовок запроса клиента следующим образом:
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await _testServerFixture.GetAccessToken());
КогдаЯ отлаживаю свой интеграционный тест, я вижу, что запрос содержит действительный токен доступа, но я все еще получаю 401 Unauthorized от API, когда я запускаю свой интеграционный тест.
После некоторого копания я нашел несколько ресурсовэто говорит о похожей проблеме с TestServer, но, как я понимаю, касается аутентификации, а не авторизации.Вот ссылки на эти ресурсы:
https://medium.com/@zbartl/authentication-and-asp-net-core-integration-testing-using-testserver-15d47b03045a
Как выполнить интеграционное тестирование ASP 5 / Core Web API с атрибутами [Authorize]
http://geeklearning.io/how-to-deal-with-identity-when-testing-an-asp-net-core-application/
Все они говорят о назначении ClaimsPrincipal для context.user с использованием пользовательского промежуточного программного обеспечения.Поскольку это основано на аутентификации, а не на авторизации, я не уверен, смогу ли я сделать что-то подобное для своего токена доступа.
Я знаю, что в моем API я могу получить доступ к HTTPContext.User и вытащитьЗначение AppId, являющееся частью токена доступа, поэтому может показаться, что и аутентификация, и авторизация используют Context.User.
Итак, прежде чем я потрачу время на создание собственного пользовательского промежуточного программного обеспечения для этой цели, я хотелпосмотрите, если кто-нибудь уже решил эту проблему или, возможно, знает о NuGet, который делает то, что мне нужно.
РЕДАКТИРОВАТЬ - РЕШЕНИЕ
Я показываю это в случае, если кто-то ещесталкивается с этой проблемой.
Я закончил сборку промежуточного программного обеспечения, которое Зак Бартлетт представил в своем блоге , но внес следующие изменения.
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);
}
}
Был один интересный"Попался".
В блоге Зака у него был код:
public const string TestingHeader = "X-Integration-Testing";
в верхней части его промежуточного программного обеспечения, а затем он ссылается на TestingHeader в тесте для ключа в коллекции заголовков следующим образом;
if (context.Request.Headers.Keys.Contains(TestingHeader)
Выполнение этого способа для меня было неудачным, пока я не поместил строковый литерал вместо переменной в предложение .Contains ().
Теперь мой интеграционный тест проходит с ответом 200 OK.:)