Двойной запрос при вызове POX REST с использованием WCF с WebHttpBinding, установленным на базовую аутентификацию - PullRequest
2 голосов
/ 22 сентября 2009

Возникла проблема при выполнении вызова POX REST с использованием WCF с WebHttpBinding, для которого установлена ​​базовая аутентификация (HttpClientCredentialType.Basic)

Вместо одного вызова от клиента с «Авторизацией: Базовая», указанной в заголовке HTTP, выполняется два вызова. Первый звонок вообще без аутентификации, на который служба отвечает 401 Несанкционированная ошибка, второй звонок с правильной информацией аутентификации.

Это, кажется, обрабатывается службой WCF без каких-либо проблем. Обращение к сторонним службам, очевидно, создает проблему, поскольку они немедленно отвечают с ошибкой.

Сервисный код:

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare,
        RequestFormat = WebMessageFormat.Xml,
        UriTemplate = "")]
    Message SendData(Message message);

}

public class Service : IService
{
    public Message SendData(Message message)
    {           return Message.CreateMessage(MessageVersion.None, String.Empty, "test");
    }
}

Код клиента:

public class Client: WebChannelFactory<IService>, IService
{
    public Client(Uri baseUri, string userName, string password)
        : base(CreateBinding(),
               baseUri)
    {
        Credentials.UserName.UserName = userName;
        Credentials.UserName.Password = password;
    }

    public Message SendData(Message requestMessage)
    {
        var channel = CreateChannel();
        Message responseMessage = channel.SendData(requestMessage);
        return responseMessage;
    }

    private static Binding CreateBinding()
    {
        var binding = new WebHttpBinding();
        binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
        return binding;
    }

}

Использование TcpTrace Я вижу это для запросов спина к спине:

POST / HTTP/1.1  
Content-Type: application/xml; charset=utf-8  
VsDebuggerCausalityData:   uIDPo2lH6p+lUOdFmrqDKGWYeQkAAAAA7+Y4QR6wNUWZmwCaasMx7xrfcJZxph9NocstwCh8NQsACQAA  
Host: localhost:9090  
Content-Length: 89  
Expect: 100-continue  
Connection: Keep-Alive  

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">test request</string>  

POST / HTTP/1.1  
Content-Type: application/xml; charset=utf-8  
VsDebuggerCausalityData: uIDPo2lH6p+lUOdFmrqDKGWYeQkAAAAA7+Y4QR6wNUWZmwCaasMx7xrfcJZxph9NocstwCh8NQsACQAA  
Authorization: Basic dGVzdDp0ZXN0  
Host: localhost:9090  
Content-Length: 89  
Expect: 100-continue  

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">test request</string> 

Примечание: только второй вызов содержит: Авторизация: Basic dGVzdDp0ZXN0 Как остановить первый запрос (без авторизации)?

Пример решения с утилитой TcpTrace можно скачать здесь:

WCF-BasicAuthenticationIssue.zip

Ответы [ 2 ]

4 голосов
/ 23 сентября 2009

Итак, основываясь на ответе Ремуса, это мой обходной путь

        public Message SendData(Message requestMessage)
    {
        var channel = CreateChannel();
        Message responseMessage;
        using (new OperationContextScope((IClientChannel)channel))
        {
            WebOperationContext.Current.OutgoingRequest
                .Headers[HttpRequestHeader.Authorization] = "Basic "
                + Convert.ToBase64String(Encoding.ASCII.GetBytes(
                Credentials.UserName.UserName + ":" + Credentials.UserName.Password));
            responseMessage = channel.SendData(requestMessage); 
        }
        return responseMessage;
    }

Я просто заставляю первый запрос выйти с базовой авторизацией

3 голосов
/ 23 сентября 2009

Проблема на самом деле связана с этими третьими лицами. По RFC 2617 Базовая аутентификация выполняется в два вызова, точно так же как Digest. При первом вызове сервер должен ответить на запрос, содержащий область:

При получении несанкционированного запрос URI в пределах
пространство защиты, сервер происхождения МОЖЕТ ответить на вызов типа
следующее:

  WWW-Authenticate: Basic realm="WallyWorld"

где "WallyWorld" - строка назначенный сервером для идентификации
пространство защиты Request-URI

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

См. Также Что случилось с флагом PreAuthenticate в WCF .

...