У меня проблема с подключением приложения WinForms к службе WCF с использованием проверки подлинности NTLM.
Оригинальное приложение было написано мной в 2005 году как мой первый код C#. С небольшими доработками все получилось. Веб-сервис был asmx с DataSets. Недавно пришло время обновить его из-за: проблем с производительностью и обновления Windows 10 на клиенте (требовалось обновление Crystal Reports 10.5.37 до x64, а официальная загрузка среды выполнения на сайте SAP не предусмотрена). Я переписал его с помощью WCF,. NET 4.8, заменив Crystal библиотекой для создания файлов Excel. В среде разработчика новая версия работает хорошо, кроме кода 500. Остальное и. NET Ядро не рассматривалось (слишком сложно объяснить; не по техническим причинам).
Когда пользователь запустил новую версию, первой непосредственной проблемой было «Доступ запрещен». Потом запустили от имени администратора. Код ошибки: «Не удалось запустить приложение из-за неправильной параллельной конфигурации». Затем я безуспешно пытался получить дополнительную информацию в средстве просмотра событий: информации не было. Инструмент sxstrace поднял доступ запрещен. Через несколько дней я получил это: я оставил комментарий в файле конфигурации, содержащий символы sh не на английском языке. После удаления комментария во время подключения произошла ошибка 500.
<\ LongStory-optional>
Приложение вызывает службу Verify, которая просто возвращает постоянное значение 1.
Сообщение об ошибке: «Тип содержимого text / html ответного сообщения не соответствует типу содержимого привязки (text / xml; charset = utf-8).
При использовании пользовательский кодировщик, убедитесь, что метод IsContentTypeSupported реализован правильно. Первые 75 байтов ответа были:
Страница не может быть отображена из-за внутренней ошибки сервера ». . Https не использовался.
Странно то, что после открытия .sv c один раз в IE ошибка исчезла до перезагрузки рабочей станции. Это доказывает, что клиент и сервер работают правильно. В то же время в старом приложении такой проблемы нет. По этой причине я попытался использовать «Веб-ссылку» вместо «Ссылка на службу». Похоже, что «Веб-ссылка» работает правильно. Дальше я пробовал разные настройки на стороне клиента. Я обнаружил, что "Service reference" работает после этого изменения: client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
С помощью инструмента fiddler я обнаружил, что обмен сообщениями почти такой же, за исключением конечного результата: до изменения у меня есть статусы 401/401 / 500, после изменения 401/401/200, другие отличия - время и значение NTLM base64, ничего больше.
Я думаю, что это не решение, а только обходной путь. Знаете ли вы, как правильно обрабатывать NTLM-аутентификацию с помощью WCF?
Важнейшие части моего кода и конфигурации:
var client = new ServiceClient();
client.ClientCredentials.Windows.ClientCredential.UserName = Dialog1.textBox1.Text;
client.ClientCredentials.Windows.ClientCredential.Domain = Dialog1.textBox2.Text;
client.ClientCredentials.Windows.ClientCredential.Password = Dialog1.textBox3.Text;
try
{
i = client.Verify().Status;
} ...
Конфигурация:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicEndpoint" sendTimeout="infinite" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://wro67zt2/AlsbWebServices/WindService/WindService.svc" binding="basicHttpBinding" bindingConfiguration="basicEndpoint" contract="WindService.IService" name="basicEndpoint"/>
</client>
</system.serviceModel>
Я считаю этот сервер боковая конфигурация не требуется. Он хорошо работает с веб-ссылкой, поэтому я могу предположить, что здесь все в порядке. Я пробовал «Windows» вместо «Ntlm», но проблема осталась прежней, он меняет строку NTLM на Negotiate в сообщениях запроса / ответа, а также количество сообщений с 3 до 2 (401/500 или 401/200).
Edit - конфигурация сервера:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2"/>
<globalization culture="en-GB" requestEncoding="utf-8" responseEncoding="utf-8"/>
<pages controlRenderingCompatibilityVersion="4.0" clientIDMode="AutoID"/>
<identity impersonate="false" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicBinding" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" realm="XXXXX"/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="WindService.Behavior" name="WindLibrary.Service">
<endpoint
address=""
binding="basicHttpBinding"
bindingConfiguration="basicBinding"
name="basicEndpoint"
bindingNamespace="http://XXXXX.com/services/prime/"
contract="WindLibrary.IService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WindService.Behavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="http" binding="basicHttpBinding" bindingConfiguration="HttpBinding" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="false"/>
</system.webServer>
</configuration>