在一些流式传输的方面,WCF存在一些需要注意的地方(我在看着你,MTOM1),由于它在执行预身份验证时存在一个基本问题,与大多数人认为应该进行的方式不同(仅会影响该通道的后续请求,而不是第一个请求)。好吧,这实际上并不是你的问题,但请跟随我的思路,最终我会解决你的问题。通常HTTP挑战工作方式如下:
- 客户端匿名连接服务器
- 服务器说,抱歉,401,我需要验证
- 客户端使用身份验证令牌连接服务器
- 服务器接受。
现在,如果您尝试在服务器上启用WCF端点上的MTOM流式传输,它将不会抱怨。但是,当您在客户端代理上配置它(因为它们必须匹配绑定)时,它将出现灾难性错误。原因是WCF试图防止的事件序列是:
- 客户端以匿名方式向服务器发送100MB文件
- 服务器说抱歉,401,我需要验证
- 客户端再次使用带有身份验证标头的100MB文件向服务器发送流
- 服务器接受。
请注意,您只需要发送100MB,而您实际上却向服务器发送了200MB。那么,这就是问题所在。答案是在第一次尝试时发送身份验证,但在WCF中没有这个可能,除非编写自定义行为。无论如何,我偏离了话题。
你的问题
首先,让我告诉你,你正在尝试的是不可能的2。现在为了让你不再转圈子,让我告诉你原因:
我觉得你现在遇到了类似的问题。如果启用消息级安全性,则客户端必须将整个数据流加载到内存中,然后才能使用ws-security所需的常规哈希函数和xml签名关闭消息。如果必须读取整个流以签署单个消息(实际上它不是一条消息,而是一个单一连续流),那么问题就出现在这里。WCF必须在“本地”流传一次以计算消息安全性,然后再次流传以将其发送到服务器。显然,这很愚蠢,因此WCF不允许流式传输数据使用消息级安全性。
因此,简单的答案是,您应该将令牌作为初始Web服务的参数或作为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;
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.None;
请注意,我在这里关闭了传输安全,因为我将使用消息检查器和自定义行为来提供传输安全:
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)
{
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中的消息安全(参见“缺点”部分)。
<security mode="Transport" /><transport clientCredentialType="IssuedToken" /></security>
。 - Joachim IsakssonTransportWithMessageCredential
模式可能是另一个选择。 - Joachim Isaksson