HTTPClient получает два 401s до успеха (отправка неправильного токена) - программирование

HTTPClient получает два 401s до успеха (отправка неправильного токена)

Я пытаюсь связаться с самообслуживающим клиентом WebAPI, используя HttpClient. Клиент создается со следующим кодом:

HttpClientHandler clientHandler = new HttpClientHandler()
{
    UseDefaultCredentials = true,
    PreAuthenticate = true
};
var client = new HttpClient(clientHandler);

на стороне сервера, которую мы установили:

HttpListener listener = (HttpListener)app.Properties[typeof(HttpListener).FullName];
listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;

в файле Startup.

Проблема заключается в том, что я получаю две (или одну после предварительной проверки) ошибки 401 перед обработкой запроса.

В fiddler последовательность выглядит следующим образом:

First request:
Authorization: Negotiate TlRMTVNTUAABAAAAl7II4gcABwAxAAAACQAJACgAAAAGAbEdAAAAD1dTMTEzLTEyMFNXVC0xMTM=
Answer:
WWW-Authenticate: Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVwonisrQOBMTKHhKwCkgCAAAAAJoAmgBGAAAABgGxHQAAAA9TAFcAVAAtADEAMQAzAAIADgBTAFcAVAAtADEAMQAzAAEAEgBXAFMAMQAxADMALQAxADIAMAAEABYAcwB3AHQALQAxADEAMwAuAGwAbwBjAAMAKgBXAFMAMQAxADMALQAxADIAMAAuAHMAdwB0AC0AMQAxADMALgBsAG8AYwAFABYAQQBMAEQASQA5ADkAOQAuAGwAbwBjAAcACACkGh0XVY3QAQAAAAA=

Second request (succeeds):
Authorization: Negotiate TlRMTVNTUAADAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAFcKI4gYBsR0AAAAPfJafWSuLL0sAXYtWCynOqg==

Итак, почему мой клиент не отправляет правильный токен авторизации в первый раз, но всегда нужен этот двухрежимный подход?

4b9b3361

Ответ 1

То, что вы испытываете, является нормальным, так работает схема аутентификации NTLM.

1: C  --> S   GET ...

2: C <--  S   401 Unauthorized
              WWW-Authenticate: NTLM

3: C  --> S   GET ...
              Authorization: NTLM <base64-encoded type-1-message>

4: C <--  S   401 Unauthorized
              WWW-Authenticate: NTLM <base64-encoded type-2-message>

5: C  --> S   GET ...
              Authorization: NTLM <base64-encoded type-3-message>

6: C <--  S   200 Ok
  • Клиент отправляет на сервер запрос GET.
  • Поскольку вам нужно пройти аутентификацию для доступа к запрашиваемому ресурсу, сервер отправляет ответ 401 Unathorized и уведомляет клиента в заголовке WWW-Authenticate, что он поддерживает аутентификацию NTLM. Таким образом, здесь вы получаете свой первый 401 код ответа.
  • Клиент отправляет имя домена и имя пользователя на сервер в заголовке Authorization. Обратите внимание, что, основываясь исключительно на этих данных, клиент еще не может быть аутентифицирован.
  • Сервер отправляет вызов клиенту. Это произвольно сгенерированное число, называемое nonce. Здесь вы получите второй код ответа 401.
  • Клиент отправляет ответ на вызов сервера, используя свой хэш пароля для шифрования случайного числа.
  • Сервер отправляет имя пользователя клиента, вызов, отправленный клиенту, и ответ, полученный от клиента контроллеру домена. Используя имя пользователя, контроллер домена извлекает хэш пароля пользователя и шифрует вызов с ним. Если результат совпадает с ответом, отправленным клиентом, клиент аутентифицируется, и сервер отправляет обратно код ответа 200 и запрашиваемый ресурс клиенту.

Ответ 2

Столкнулся с подобной проблемой и прошел множество ответов, в которых никто из них не работал. Следующие работали, и у него нет двух 401:

var credential = new NetworkCredential("username", "password", "domainname");
var myCache = new CredentialCache();

// Add the target Uri to the CredentialCache with credential object
myCache.Add(new Uri("http://targeturi/"), "NTLM", credential);

// Create an HttpClientHandler to add some settings
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = true;
handler.Credentials = myCache;

// Create an HttpClient with the handler object
httpClient = new HttpClient(handler);

// Wait to get the reponse, and you can use the reponse in your code
HttpResponseMessage response = await httpClient.GetAsync(resourceUri);

Источник

Ответ 3

поведение по умолчанию, когда он отправляет только учетные данные после получения ответа HTTP 401 Not Authorized.

Вручную добавление заголовка учетных данных представляется лучшим решением.

Подробнее в этом сообщении