Использование службы REST WCF с обычной аутентификацией с использованием HttpClient.GetAsync () приводит к (401) несанкционированному

2

Я пытаюсь подключиться к REST-службе HttpClient с помощью HttpClient с использованием HttpClient аутентификации, но получаю (401) неавторизованным. Когда я получаю доступ к той же конечной точке из веб-браузера, ввод одного и того же имени пользователя и пароля приводит к успеху. Аутентификация на стороне сервиса выполняется через UserNamePasswordValidator. Я оставляю метод Validate пустым для целей тестирования, поэтому все запросы должны быть действительными. Тем не менее, вызов GetAsync() приводит к (401) несанкционированному. Когда я устанавливаю точку останова в методе Validate, я могу проверить, что переданы правильные значения. Есть ли объяснение этому поведению?

Клиент

using (var httpClient = new HttpClient())
{
    var authString = "admin:admin";
    var authEncoded = Encoding.GetEncoding("ISO-8859-1").GetBytes(authString);
    var authBase64String = Convert.ToBase64String(authEncoded);
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authBase64String);
    httpClient.BaseAddress = new Uri(UriFactory.GetServiceUrl());

    using (var response = await httpClient.GetAsync(serviceDomain))
    {
        string responseData = await response.Content.ReadAsStringAsync();
        return JsonConverter.FromJson<TResponse>(responseData);
    }
}

Сервис

public class CustomUserNameValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
    }
}

Это конфигурация сервиса

<system.serviceModel>
<bindings>  
  <webHttpBinding>  
    <binding name="HttpsBinding">  
      <security mode="Transport">  
        <transport clientCredentialType="Basic" />  
      </security>  
    </binding>  
  </webHttpBinding>  
</bindings>  

<services>
  <service behaviorConfiguration="MyServiceBeahvior" name="ServiceImplementation">
    <endpoint address="status"        binding="webHttpBinding" bindingConfiguration="HttpsBinding" contract="Status.IStatusService"            behaviorConfiguration="MyWebBahviorr"/>
    <endpoint address="mex"           binding="mexHttpsBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses />
    </host>
  </service>
</services>

<behaviors>
  <serviceBehaviors>
    <behavior name="MyServiceBeahvior">
      <serviceMetadata httpsGetEnabled="True" />
      <serviceDebug includeExceptionDetailInFaults="True" />
    </behavior>
  </serviceBehaviors>
  <endpointBehaviors>
    <behavior name="MyWebBahvior">
      <webHttp automaticFormatSelectionEnabled="false" />
    </behavior>
  </endpointBehaviors>
</behaviors>

_oServiceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
_oServiceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();

Связь по HTTPS с самозаверяющим сертификатом.

  • 1
    Я бы сравнил код с запросами браузера, используя инструмент сетевого мониторинга, такой как fiddler
  • 1
    Спасибо за совет, который я смог решить мою проблему с этим инструментом Fiddler, это очень удобно! Благодарю.
Теги:
dotnet-httpclient
wcf
basic-authentication

2 ответа

1
Лучший ответ

Наконец, я смог найти свою проблему с помощью Fiddler. Я отправлял запрос без последней косой черты (например, https://localhost: 4444/status вместо https://localhost: 4444/status/). Веб-браузер смог обработать перенаправление, но HttpClient не удалось.

  • 1
    Вы должны пометить свой пост как ответ, если это была ваша проблема.
  • 0
    Только Stackoverflow не позволяет мне сделать это до завтра. Видимо, вы не можете принять свой ответ на ваши вопросы в течение первых двух дней.
Показать ещё 1 комментарий
0

Прежде всего следует отметить, что CustomUsernamePasswordValidator доступен только при наличии учетных данных клиента - UserName.

    <bindings>
      <wsHttpBinding>
        <binding name="wsbd">
          <security mode="Message">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
</bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="svbhv">
          <serviceAuthorization principalPermissionMode="Custom">
            <authorizationPolicies>
              <add policyType="Server7.CustAuthorPolicy,Server7"/>
            </authorizationPolicies>
          </serviceAuthorization>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Server7.MyCustUserNamePassValidator,Server7"/>
          </serviceCredentials>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>

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

ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;

Я сделал демо, желаю, чтобы это было полезно для вас. Серверная сторона.

    public interface IService1
    {
        [OperationContract]
        [WebGet]
        string GetData(int value);

}
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }
}

Config.

<system.serviceModel>
    <services>
      <service name="WcfService3.Service1">
        <endpoint address="" binding="webHttpBinding" contract="WcfService3.IService1" bindingConfiguration="mybinding" behaviorConfiguration="rest"></endpoint>
        <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"></endpoint>
      </service>
    </services>
    <bindings>
      <webHttpBinding>
        <binding name="mybinding">
          <security mode="Transport">
            <transport clientCredentialType="Basic"></transport>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="rest">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

Сторона клиента.

  ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
    using (var httpClient = new HttpClient())
    {

        var authString = "administrator:abcd1234!";
        var authEncoded = Encoding.UTF8.GetBytes(authString);
        var authBase64String = Convert.ToBase64String(authEncoded);
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",authBase64String);

        var response = httpClient.GetAsync("https://127.0.0.1:8863/Service1.svc/getdata?value=100");
        string responsedata = response.Result.Content.ReadAsStringAsync().Result;
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(responsedata);
        Console.WriteLine(doc.InnerText);
    }

Результат.
Изображение 174551

  • 0
    Большое спасибо за усилия! Я смог найти решение сам, тем не менее, я очень благодарен за этот ответ!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню