Как использовать класс TestServer в оперативной памяти Asp.Net Core 2.0 для интеграционных тестов, когда моему API требуется токен авторизации? - PullRequest
0 голосов
/ 23 мая 2018

Я работаю над веб-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.:)

1 Ответ

0 голосов
/ 24 мая 2018

Мне удалось найти решение после публикации в блоге Заха Бартлетта и внесения небольших изменений в заголовок Authentication.Код показан как редактирование в моем оригинальном посте выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...