Web API в тестировании интеграции памяти - аутентификация между двумя сервисами - PullRequest
0 голосов
/ 05 июня 2018

Я искал много сообщений здесь о моей проблеме, но не нашел ничего связанного с тем, чего я пытаюсь достичь.

Я создал микросервис Web API для обработки аутентификации пользователя.Служба использует систему идентификации и выдает токены на предъявителя.У меня есть другой веб-API, который защищен с помощью атрибута [Authroize] на контроллерах.Обе службы взаимодействуют с одной и той же базой данных через Entity Framework.

При создании этой инфраструктуры мне пришлось преодолеть одно препятствие: обеим службам требовался один и тот же ключ компьютера в своих файлах web.configs.Когда все развернуто, оно прекрасно работает.

Однако я пытаюсь написать несколько интеграционных тестов для моего основного API с использованием Microsoft Owin TestServer.Это позволяет мне писать интеграционные тесты для копии API в памяти, которая также использует копию базы данных в памяти с использованием миграций инфраструктуры сущностей.

Я успешно создал интеграционные тесты для моей пользовательской службы.Однако я изо всех сил пытаюсь заставить интеграционные тесты работать для моего основного сервиса.Я создал решение с новым тестовым проектом.Я также связал в своем пользовательском сервисе и основном сервисе.В начальной загрузке для интеграционных тестов я раскручиваю в памяти копию каждого сервиса, используя каждый сервис Startup.cs.

Все работает нормально, пока я не попытаюсь поразить контроллер, защищенный атрибутом [Authorize].Я успешно подключился к службе пользователя, чтобы зарегистрировать пользователя, активировать его и получить токен на предъявителя.Затем я передаю это в запросе к основному сервису в заголовке аутентификации.Однако я всегда получаю несанкционированный ответ от службы.

Я подозреваю, что это снова связано с машинными ключами, и я пытался вставить этот же машинный ключ в файл App.config в рамках проекта тестирования интеграции.Это не имело никакого значения.

Если кому-то удалось реализовать этот сценарий, я был бы очень признателен за любые советы о том, что может быть причиной проблемы.Я не вставлял ни одного кода, так как в нем много всего, но был бы рад вставить любые подробности.

Тестирование таким способом является супер быстрым и действительно мощным.Однако, кажется, что не хватает информации о том, как заставить это работать.

РЕДАКТИРОВАТЬ

Вот некоторый код по запросу.Два API в памяти создаются в OneTimeSetUp следующим образом:

_userApi = TestServer.Create<UserApi.Startup>();
_webApi = TestServer.Create<WebApi.Startup>();

Авторизованный HttpClient затем берется из API следующим образом:

var client = _webApi.HttpClient;
var authorizationValue = new AuthenticationHeaderValue("Bearer", token);
client.DefaultRequestHeaders.Authorization = authorizationValue;

"токен" получается изобслуживание пользователя.

Затем выполняется GET с использованием клиента следующим образом:

var result = await client.GetAsync(uri);

РЕДАКТИРОВАТЬ 2

Я также должен отметить, что япрошли аутентификацию интеграционных тестов, работающих в Сервисе пользователя.Проблема только в том, когда я пытаюсь использовать оба сервиса вместе.Например, получить токен из службы пользователя и использовать этот токен для аутентификации в моей основной службе.База данных сущности в памяти создается следующим образом:

AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(TestContext.CurrentContext.TestDirectory, string.Empty));
using (new ContractManagerDatabase())
{
System.Data.Entity.Database.SetInitializer(new DropCreateDatabaseAlways<ContractManagerDatabase>());
}

1 Ответ

0 голосов
/ 08 июня 2018

Так что после нескольких дней борьбы с этим я наконец нашел решение.Первым делом я переместил интеграционные тесты обратно в основной веб-API.Сделав шаг назад и подумав о проблеме, я понял, что, создавая отдельное решение и раскручивая свою пользовательскую службу и веб-API в памяти, все, что я действительно проверял, - это Identity Framework, а не сам API.

У меня отлично работают интеграционные тесты в моей пользовательской службе для вызовов без аутентификации и с аутентификацией.Мне казалось, что я должен быть в состоянии сделать то же самое с веб-API и не полагаться на пользовательскую службу.

Я подумал, что должен иметь возможность «обойти» атрибут [Authorize] для проверкиAPI.После некоторых поисков в Google я обнаружил следующую статью, которая была наиболее ценной для обеспечения работоспособности решения:

https://blogs.taiga.nl/martijn/2016/03/10/asp-net-web-api-owin-authenticated-integration-tests-without-authorization-server/

Ключевые вещи для меня были следующие:

  1. HTTP-клиент должен был быть сконструирован по-другому для теста.

    var client = new HttpClient(_webApp.Handler) {BaseAddress = new Uri("http://localhost")};
    
  2. Вызов GET должен был быть сконструирован по-другому для теста.

    token = token == string.Empty ? GenerateToken(userName, userId) : token;
    var request = new HttpRequestMessage(HttpMethod.Get, uri);
    request.Headers.Add("Authorization", "Bearer " + token);
    var client = GetAuthenticatedClient(token);
    return await client.SendAsync(request);
    
  3. Токен необходимо сгенерировать следующим образом.Мне также нужно было добавить претензию к идентификатору пользователя, поскольку она взята из запроса в контроллере.

    private static string GenerateToken(string userName, int userId)
    {
        var claims = new[]
        {
            new Claim(ClaimTypes.Name, userName),
            new Claim(ClaimTypes.NameIdentifier, userId.ToString()) 
        };
        var identity = new ClaimsIdentity(claims, "Test");
    
        var properties = new AuthenticationProperties { ExpiresUtc = DateTime.UtcNow.AddHours(1) };
        var ticket = new AuthenticationTicket(identity, properties);
        var format = new TicketDataFormat(_dataProtector);
        var token = format.Protect(ticket);
        return token;
    }
    

Я надеюсь, что этот пост поможет другим с подобными проблемами и спасибо всемкто способствовал.

...