Ответ 1
WCF имеет несколько областей с потоковой передачей (я смотрю на вас, MTOM 1) из-за фундаментальной проблемы в том, как он не может выполнить предварительную аутентификацию, как большинство людей думают, что должно (это влияет только на последующие запросы для этого канала, а не на первый запрос) Хорошо, так что это не совсем ваша проблема, но, пожалуйста, следуйте за мной, пока я доберусь до вас. Обычно HTTP-запрос работает следующим образом:
- клиент обращается к серверу анонимно
- сервер говорит, извините, 401, мне нужна аутентификация
- клиент обращается к серверу с токеном аутентификации
- сервер принимает.
Теперь, если вы попытаетесь включить потоки MTOM в конечной точке WCF на сервере, он не будет жаловаться. Но когда вы настраиваете его на клиентском прокси (как и должны, они должны соответствовать привязкам), он будет взрываться в огненной смерти. Причиной этого является то, что указанная выше последовательность событий, которые WCF пытается предотвратить, такова:
- клиентский поток 100MB файл на сервер анонимно в одном POST
- сервер говорит, извините, 401, мне нужна аутентификация.
- клиент снова передает файл 100 МБ на сервер с заголовком аутентификации
- сервер принимает.
Обратите внимание, что вы только что отправили 200 МБ на сервер, когда вам нужно было отправить 100 МБ. Ну, это проблема. Ответ заключается в том, чтобы отправить аутентификацию с первой попытки, но это невозможно в WCF без написания пользовательского поведения. Во всяком случае, я отвлекаюсь.
Ваша проблема
Прежде всего, позвольте мне сказать вам, что то, что вы пытаетесь, невозможно 2. Теперь, чтобы вы перестали вращать свои колеса, позвольте мне сказать вам, почему:
Мне кажется, что вы теперь блуждаете в подобном классе проблем. Если вы включите защиту уровня сообщений, клиент должен загрузить весь поток данных в память, прежде чем он сможет фактически закрыть сообщение с помощью обычной хэш-функции и подписи xml, требуемой ws-security. Если он должен прочитать весь поток, чтобы подписать единственное сообщение (которое на самом деле не является сообщением, но оно представляет собой единственный непрерывный поток), вы можете увидеть проблему здесь. WCF должен будет передать его один раз "локально", чтобы вычислить безопасность сообщения, а затем передать его снова, чтобы отправить его на сервер. Это явно глупо, поэтому WCF не позволяет обеспечить безопасность сообщений для потоковой передачи данных.
Итак, простой ответ заключается в том, что вы должны отправить токен либо в качестве параметра в исходную веб-службу, либо в качестве заголовка SOAP, и использовать его для проверки. Вы не можете использовать WS-Security для этого. Честно говоря, это не просто проблема WCF - я не вижу, как она может практически работать для любых других стеков.
Решение проблемы с MTOM
Это просто пример того, как я решил проблему потоковой передачи MTOM для базовой проверки подлинности, поэтому, возможно, вы могли бы избавиться от этого и реализовать что-то подобное для вашей проблемы. Суть его в том, что для того, чтобы включить свой собственный инспектор сообщений, вам необходимо отключить все понятия безопасности на прокси-сервере клиента (он остается включенным на сервере), кроме уровня транспорта (SSL):
this._contentService.Endpoint.Behaviors.Add(
new BasicAuthenticationBehavior(
username: this.Settings.HttpUser,
password: this.Settings.HttpPass));
var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding;
binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.None; // Do not provide
Обратите внимание, что я отключил транспортную безопасность здесь, потому что я буду обеспечивать, чтобы я использовал инспектор сообщений и пользовательское поведение:
internal class BasicAuthenticationBehavior : IEndpointBehavior
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationBehavior(string username, string password)
{
this._username = username;
this._password = password;
}
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{
var inspector = new BasicAuthenticationInspector(
this._username, this._password);
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
internal class BasicAuthenticationInspector : IClientMessageInspector
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationInspector(string username, string password)
{
this._username = username;
this._password = password;
}
public void AfterReceiveReply(ref Message reply,
object correlationState) { }
public object BeforeSendRequest(ref Message request,
IClientChannel channel)
{
// we add the headers manually rather than using credentials
// due to proxying issues, and with the 101-continue http verb
var authInfo = Convert.ToBase64String(
Encoding.Default.GetBytes(this._username + ":" + this._password));
var messageProperty = new HttpRequestMessageProperty();
messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
request.Properties[HttpRequestMessageProperty.Name] = messageProperty;
return null;
}
}
Итак, этот пример предназначен для всех, кто страдает проблемой MTOM, но также как скелет для реализации чего-то подобного для аутентификации вашего токена, сгенерированного первичной службой токенов, защищенной WIF.
Надеюсь, что это поможет.
(1) Большие данные и потоковое вещание
(2) Безопасность сообщений в WCF (см. "Недостатки".)