WCF在流媒体处理方面存在一些问题(我正在看您,MTOM 1),这是由于它无法执行大多数人认为应该起作用的方式进行预身份验证的根本问题(它只会影响对该频道的后续请求) ,而不是第一个请求)好吧,所以这不完全是您的问题,但请继续,因为我将在最后解决您的问题。通常,HTTP挑战的工作方式如下:
- 客户端匿名访问服务器
- 服务器说对不起,401,我需要验证
- 客户端使用身份验证令牌访问服务器
- 服务器接受。
现在,如果您曾经尝试在服务器上的WCF终结点上启用MTOM流,它将不会抱怨。但是,当您在客户端代理上配置它时(如您所愿,它们必须匹配绑定),它会爆炸而死。其原因是WCF试图阻止的上述事件序列是:
- 客户端在单个POST中以匿名方式将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; // 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中的消息安全性(请参阅“缺点”)。
<security mode="Transport" /> <transport clientCredentialType="IssuedToken" /> </security>