Вызов веб-API из приложения MVC со встроенной проверкой подлинности Windows

У меня есть приложение MVC и связанный с ним проект веб-API, которые размещены на удаленном сервере в IIS. Они используют один и тот же пул приложений. Всякий раз, когда я пытаюсь выполнить вызов веб-API из приложения MVC, я получаю сообщение об ошибке 403, которое, по-видимому, связано с неправильными учетными данными, переданными HttpClientHandler. У меня есть

UseDefaultCredentials = true 

а я пробовал ставить

Credentials = CredentialCache.DefaultNetworkCredentials

но ни один из них не позволяет пройти запрос API.

Настройка пула приложений на использование моего имени пользователя/пароля AD позволяет проходить всем запросам API, а также вызов API непосредственно из Postman возвращает данные правильно.

Я предполагаю, что IIS AppPool [имя пула] перенаправляется в запросе, а правильные учетные данные никогда не передаются. Можно ли как-то обойти это, не делая API небезопасным (т.е. только несколько доменных групп должны иметь к нему доступ)?

Пример вызова, который я делаю в API из приложения MVC

    public async Task<HttpResponseMessage> CreateIncident(Incident model)
    {
        using (var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }))
        {
            var newIncident = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json");
            var response = await client.PostAsync(hostUri, newIncident);
            return response;
        }
    }

person Robert McCoy    schedule 27.02.2017    source источник
comment
Вы вообще через прокси заходите?   -  person joshmcode    schedule 28.02.2017
comment
Нет, все это размещено на внутреннем сервере, и все звонки проходят исключительно через этот сервер. Прокси нет. Как я уже сказал, Postman и прямые вызовы API с моего компьютера проходят, но, похоже, .NET Core не может олицетворять запросы, и я надеялся, что кто-то другой недавно попал в это, что может дать более актуальную информацию. решение, чем некоторые из 6+ месяцев, которые немного устарели в .NET Core.   -  person Robert McCoy    schedule 28.02.2017


Ответы (3)


Без дополнительной информации трудно сказать наверняка, но проблема, вероятно, связана с двойной проверкой подлинности, которую вы пытаетесь выполнить.

  1. клиентское приложение (браузер в случае веб-сайта) аутентифицирует пользователя, которого отправляет клиент
  2. аутентификация на сервере (приложение MVC)
  3. затем приложение MVC пытается передать аутентификацию веб-службе.

Когда мне нужно было выполнить аналогичную задачу, я не смог заставить HttpClient работать. Я попробовал ряд предложенных решений из этого вопроса, Как заставить HttpClient передавать учетные данные вместе с запросом?. Хотя это было информативно, в частности, эта часть ответа BlackSpy объяснила, почему:

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

В итоге я использовал WebClient (с обязательным таргетингом на .NET framework) с чем-то вроде этого в приложении MVC (в данном случае загрузив файл из веб-API):

private async Task GetFileAsync(Identity identity, string serviceAddress, Stream stream)
{
    var windowsIdentity = Identity as WindowsIdentity;

    if (windowsIdentity == null)
    {
        throw new InvalidOperationException("Identity not a valid windows identity.");
    }

    using (windowsIdentity.Impersonate())
    {
        using (var client = new WebClient { UseDefaultCredentials = true })
        {
            var fileData = await client.DownloadDataTaskAsync(serviceAddress);
            await stream.WriteAsync(fileData, 0, fileData.Length);
            stream.Seek(0, SeekOrigin.Begin);
        }
    }
}

Хотя требование ориентироваться на полную платформу не позволяет этому решению быть .NET Core, но похоже, что с тех пор оно было добавлено.

Добавить WebClient в новый контракт System.Net.WebClient

Этот PR портирует System.Net.WebClient на corefx. Код в основном взят с рабочего стола, а затем немного стилистически очищен. Единственным существенным изменением кода было удаление сотен строк сложного кода на основе обратного вызова APM и замена его несколькими основными асинхронными методами. Можно еще много чего почистить, но с функциональной точки зрения этого достаточно.

person David Culp    schedule 28.02.2017
comment
Я видел это решение (и слишком много читал о двойном прыжке), но я не думаю, что веб-клиент еще находится в ядре. Они влили его в репозиторий, но, насколько я могу судить, он никогда не был включен ни в один RC или Preview, и я не могу сослаться на него в Visual Studio. Я надеялся, что у кого-то будет более современная реализация олицетворения, так как в другом потоке переполнения стека, который я читал, было устаревшее решение, которое больше не работало. Я бы не хотел возвращаться к .NET Framework, но это тоже может привести. Спасибо! - person Robert McCoy; 28.02.2017
comment
Эй, Дэвид, я наконец нашел решение, которое искал (Да... это заняло некоторое время). Вы можете найти обсуждение проблемы на GitHub здесь, а пользователь ilanc разместил ссылку на пример репозитория внизу обсуждения. github.com/aspnet/Home/issues/1805 - person Robert McCoy; 02.03.2017

Не видя кода сложно сказать. Вы пробовали без установки параметра Credentials? Я бы запустил fiddler и сравнил запрос, отправленный приложением MVC и почтальоном.

person Shane Ray    schedule 27.02.2017
comment
Я посмотрел на результаты Fiddler. Почтальон даже не ведет никаких переговоров из-за встроенной аутентификации Windows, сервер автоматически определяет мои учетные данные для входа. Что касается приложения MVC, оно отправляет авторизацию согласования с запросом и возвращает 401. Вот почему я думаю, что API получает информацию IIS AppPool и отправляет ее в качестве учетных данных. Я также добавил немного примера кода в вопрос. - person Robert McCoy; 28.02.2017
comment
Вы пытались удалить UseDefaultCredentials = true? - person Shane Ray; 28.02.2017
comment
Да вроде никак не повлияло. Также попытался сделать PreAuth = false и установить Credentials на что-то. Можно просто пойти с решением Дэвида и сделать приложение не полностью основным. - person Robert McCoy; 28.02.2017

Вы можете узнать, как выдать себя за уже аутентифицированного пользователя (Windows) на этой странице обсуждения GitHub: https://github.com/aspnet/Home/issues/1805

У ilanc есть действительно хорошая демонстрация со ссылкой внизу.

person Robert McCoy    schedule 01.03.2017