gpt4 book ai didi

c# - 如何使用 ClientInspector 修改 WCF 消息头的 MustUnderstand

转载 作者:太空狗 更新时间:2023-10-29 20:29:12 32 4
gpt4 key购买 nike

我正在从 WCF 客户端调用非 WCF 服务。 WCF 客户端包括设置为“1”的“MustUnderstand” header 属性。这是一个典型的 SOAP 请求:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="_0">
<u:Created>2010-08-23T20:48:52.680Z</u:Created>
<u:Expires>2010-08-23T20:53:52.680Z</u:Expires>
</u:Timestamp>
<o:UsernameToken u:Id="uuid-72ea0c0a-43aa-43b2-bed7-c2da13624105-1">
<o:Username>blablabla</o:Username>
<o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">blablabla</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<HeartbeatRequest xmlns="http://removed">
<DateTime xmlns="">8/23/2010 4:48:51 PM</DateTime>
<Message xmlns="">123</Message>
</HeartbeatRequest>
</s:Body>

现在,这是我为此得到的回复。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<Misunderstood qname="o:Security" xmlns="http://www.w3.org/2002/06/soap-faults" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" />
</soapenv:Header>
<soapenv:Body>
<soapenv:Fault xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>soapenv:MustUnderstand</faultcode>
<faultstring>WSWS3173E: Error: Did not understand &quot;MustUnderstand&quot; header(s):{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security</faultstring>
</soapenv:Fault>
</soapenv:Body>

请注意 MustUnderstand 未被理解的部分。

此服务的所有者表示他们允许具有 WSSE 命名空间前缀但实际上不在 XSD 中的元素,并进行一些其他处理以阻止他们接受 MustUnderstand="1"所以我必须找到一种使用 MustUnderstand="0"发送消息的方法。

我尝试使用 MessageHeader 属性在代理客户端的 MessageContract 中更改此设置,但这没有帮助。

接下来,我实现了一个自定义客户端消息检查器。我根据 MSDN 为自定义行为扩展元素和 IEndpointBehavior 创建了类,这些都是微不足道的,但这里是为了完整性:

    public class ExClientBehavior : IEndpointBehavior
{
#region IEndpointBehavior Members

public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
// no op
}

public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
ExInspector inspector = new ExInspector();
clientRuntime.MessageInspectors.Add(inspector);
}

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
// no op
}

public void Validate(ServiceEndpoint endpoint)
{
// no op
}

#endregion
}


public class ExClientBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(ExClientBehavior); }
}

protected override object CreateBehavior()
{
return new ExClientBehavior();
}
}

现在是真正的 Inspector:

    public class ExInspector : IClientMessageInspector
{

#region IClientMessageInspector Members

public void AfterReceiveReply(ref Message reply, object correlationState)
{
// no op
return;
}

public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);

Message newMessage = buffer.CreateMessage();

newMessage.Headers.RemoveAt(0);

newMessage.Headers.Add(MessageHeader.CreateHeader
(
request.Headers[0].Name,
request.Headers[0].Namespace,
string.Empty,
false,
string.Empty,
request.Headers[0].Relay
)
);

request = newMessage;

return null;
}

#endregion
}

如您所见,我正在通过缓冲副本创建一个新请求,然后删除安全 header (只有一个 header )并添加一个新的 MustUnderstand 设置为 false(我为什么要这样做?MessageHeader.MustUnderstand 是只读)。我在这个方法中设置了一个断点,确实,添加了新的 header ,将 newMessage 写回到请求中,并且 newMessage.Headers[0].MustUnderstand 和 request.Headers[0].MustUnderstand 都为 false此方法结束。

但是,发送到服务的消息在标题中仍然包含 MustUnderstand="1"!!!!!

这是包含上述行为的 app.config:

<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WebServiceSOAP" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint
address="https://removed"
behaviorConfiguration="ovrExClientBehavior"
binding="basicHttpBinding"
bindingConfiguration="WebServiceSOAP"
contract="EWebService.EWebService"
name="WebServiceSOAP" />
</client>
<extensions>
<behaviorExtensions>
<add name="exClientBehavior" type="ExMessageInspector.ExClientBehaviorExtensionElement, ExMessageInspector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="ovrExClientBehavior">
<exClientBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>

所以我的问题是:是否可以像上面那样或以类似方式更改传出消息上的 MustUnderstand?或者在检查员替换安全 header 之后,它是否会在管道中被强行改回 true?

注意:服务所有者说他们只知道另一个组织在 .NET 中使用此服务,并且该消费者必须从根本上抛弃 WCF 和 WSE 并创建 SOAP 消息 - 并处理回复 - 从头开始​​,可能使用 POX POST 或类似的东西。我们真的希望避免这种情况,因为我们需要在服务上调用许多操作。

此外,我们需要完整地保留消息的主体和属性。

任何帮助将不胜感激!!

最佳答案

我想知道如果供应商不遵守互操作性标准,为什么还要存在这些标准。如果客户端检查器不起作用,您可以尝试实现自定义消息编码器并在那里修改 header 。

编辑:

这里的问题是,如果您同时声明服务不必理解带有凭据的 header = 不必使用它们,那么为什么要发送用户凭据进行身份验证。你真的需要它们吗?

根据您的要求,还有其他方法。你需要时间戳吗?是否在服务器上检查了时间戳?您是否只有一个用户来处理所有调用,或者您是否必须在调用之间分配不同的用户?

如果您不需要时间戳或未选中时间戳并且您只有一个用户名和密码,最简单的方法是不使用 TranportWithMessageCredential 安全模式。改用纯传输并将 header 描述放在客户端端点配置中,例如:

<client>
<endpoint address="https://removed" binding="basicHttpBinding" bindingConfiguration="WebServiceSOPA" contract="EWebService.EWebService" name="WebServiceSOAP">
<headers>
<wsse:Security s:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:UsernameToken wsu:Id="SecurityToken-3f7f983f-66ce-480d-bce6-170632d33f92" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>User</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Pwd123</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</headers>
</endpoint>
</client>

如果您有多个用户名,或者如果您需要带有实际数据的真实时间戳,您可以使用相同的方法,但您可以在代码中创建自定义 header 而不是静态配置,从而避免 WCF 安全性。这可以使用消息检查器来完成。

关于c# - 如何使用 ClientInspector 修改 WCF 消息头的 MustUnderstand,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3551738/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com