坚持使用凭据连接到远程 SOAP 服务

Stuck connecting to remote SOAP service with credentials

我需要连接到远程 SOAP 服务。几天来,我一直在尝试 所有 许多配置,但都没有成功。

使用 SoapUI 时连接正常。 从我的 .net 应用程序调用时连接失败。

错误:未提供用户名。在 ClientCredentials 中指定用户名。

我的应用程序和远程应用程序都在 IIS 上 运行。

这是远程绑定:

<bindings>
  <wsHttpBinding>
    <binding name="WsHttpBinding_Default" maxReceivedMessageSize="524288000" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00">
      <security mode="TransportWithMessageCredential">
        <transport clientCredentialType="None" />
        <message clientCredentialType="UserName" establishSecurityContext="false" />
      </security>
    </binding>
  </wsHttpBinding>
</bindings>

SoapUI 使用以下配置工作:

当我检查来自 SoapUI 的原始请求时,它正在发送:

POST https://domain.name/TestNode/V_ServicePartenaireDS/v5.svc HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8;action="http://URI/getUser"
Authorization: Basic UEFSVFxzdmMtaWlzYmsdfsdfsdfphZG1pbjEyMy0t
Content-Length: 1371
Host: proxy-int.part.lan.net
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:v2="http://cnc.fr/Circe/Partenaires/v2.7">
    <soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security soap:mustUnderstand="true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsu:Timestamp wsu:Id="TS-268FDC1861EA4F5F3C154297086643492">
                <wsu:Created>2018-11-23T11:01:06Z</wsu:Created>
                <wsu:Expires>2018-11-23T16:34:26Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse:UsernameToken wsu:Id="UsernameToken-268FDC1861EA4F5F3C154297086643491">
                <wsse:Username>PART\svc-iisbackend</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">pwd</wsse:Password>
                <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">yi71/jQzUJw/lzReixSgOA==</wsse:Nonce>
                <wsu:Created>2018-11-23T11:01:06.434Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
        <wsa:Action>http://UIR/getUser</wsa:Action>
    </soap:Header>
    <soap:Body>
        <v2:getUser>
            <!--Optional:-->
            <v2:id>200785</v2:id>
        </v2:getUser>
    </soap:Body>
</soap:Envelope>

上面的一切都有效


现在,我在 .net 4.6.1 应用程序中做什么?我正在尝试发送与 SoapUI 发送的请求相同的请求。

这是我的做法:web.config 使用端点、绑定和行为扩展。扩展行为实现了调用检查器(来自 ApplyClientBehavior)的端点行为,我从中使用 BeforeSendRequest 添加两件事:

以下是实施的细节。

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WsHttpBinding_Default" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00">
                <security mode="Transport">
                    <transport clientCredentialType="None"/>
                </security>
                <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
            </binding>
            <binding name="WsHttpBinding_Authentication" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00">
                <security mode="Transport">
                    <transport clientCredentialType="Basic" />
                    <message clientCredentialType="UserName" />
                </security>
                <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
            </binding>
        </wsHttpBinding>
        <basicHttpBinding>
            <binding name="BasicHttp_Default" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00" />
        </basicHttpBinding>
    </bindings>
    <extensions>
        <behaviorExtensions>
            <add name="localSecurity" type="Users.UsersImplementation.Service.ImplementationCommon.BehaviorExtensionBasicAuthent, Users.UsersImplementation"/>
        </behaviorExtensions>
    </extensions>
    <behaviors>
        <endpointBehaviors>
            <behavior name="LocalWsBehavior">
                <callbackDebug includeExceptionDetailInFaults="true" />  
                <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
                <localSecurity/>
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <client>
        <endpoint address="https://domain/TestNode/V_ServiceUser/v5.svc" behaviorConfiguration="LocalWsBehavior" binding="wsHttpBinding" bindingConfiguration="WsHttpBinding_Authentication" contract="App.UserDSContract.IServiceUserDS" name="" />
        <!--<headers>
          <wsse:Security xmlns:soap="schemas.xmlsoap.org/soap/envelope" soap:mustUnderstand="true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsu:Timestamp wsu:Id="TS-268FDC1861EA4F5F3C154289160250080">
              <wsu:Created>2018-11-22T15:15:02Z</wsu:Created>
              <wsu:Expires>2018-11-22T18:33:22Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse:UsernameToken wsu:Id="UsernameToken-268FDC1861EA4F5F3C154289160250079">
              <wsse:Username>PART\svc-iisbackend</wsse:Username>
              <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">pws</wsse:Password>
              <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">NcDsjgc1/cRNuHVMR7kJBw==</wsse:Nonce>
              <wsu:Created>2018-11-22T15:15:02.499Z</wsu:Created>
            </wsse:UsernameToken>
          </wsse:Security>
        </headers>
      </endpoint>-->        
    </client>
</system.serviceModel>

沿着 c# class 的链,我们找到这段代码:

    void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
    {
        // nothing to do here
    }

    object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        SoapSecurityHeader header = new SoapSecurityHeader("PART\svc-iisbackend", "pwd");
        request.Headers.Add(header);
        HttpRequestMessageProperty httpRequestMessage;
        object httpRequestMessageObject;
        if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
        {
            httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
            if (string.IsNullOrEmpty(httpRequestMessage.Headers[HttpRequestHeader.Authorization]))
            {
                httpRequestMessage.Headers[HttpRequestHeader.Authorization] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("PART\svc-iisbackend-sagre" + ":" + "admin123--")); 
            }
            request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
        }
        else
        {
            httpRequestMessage = new HttpRequestMessageProperty();
            httpRequestMessage.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("PART\svc-iisbackend-sagre" + ":" + "admin123--")));
            request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
        }
        return header.Id;
    }

在远程服务器端生成的 SOAP 信封*是这样的:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://UIR/getUser</a:Action>
        <a:MessageID>urn:uuid:2b66b328-778f-4967-925a-01b75d9ab607</a:MessageID>
        <a:ReplyTo>
            <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
        </a:ReplyTo>
        <wsse:Security s:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsu:Timestamp wsu:Id="TS-f7abfe27c28e4209b8c028ef78bdf739">
                <wsu:Created>2018-11-23T14:37:46.59Z</wsu:Created>
                <wsu:Expires>2018-11-23T16:37:46.59Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse:UsernameToken wsu:Id="UsernameToken-aff0ea1c178c4843babf4afa5cd280f6">
                <wsse:Username>PART\svc-iisbackend</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">pwd</wsse:Password>
                <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">qdiFSufkRLuPRHTwDYPzBDTu1/o=</wsse:Nonce>
                <wsu:Created>2018-11-23T14:37:46.593Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
        <a:To s:mustUnderstand="1">https://domain.url/V_ServiceUser/v5.svc</a:To>
    </s:Header>
    <s:Body>
        <getUser xmlns="http://url">
            <id>200472</id>
        </getUser>
    </s:Body>
</s:Envelope>

直到现在我已经关注了许多博客和文档,但我仍然卡住了 :D

*要让消息到达服务器,我需要使用默认绑定配置 WsHttpBinding_Default。当我使用 WsHttpBinding_Authentication 时,请求似乎没有被远程服务器处理。

我尝试使用绑定配置,但到目前为止运气不好。

错误:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>
        <a:RelatesTo>urn:uuid:2b66b328-778f-4967-925a-01b75d9ab607</a:RelatesTo>
    </s:Header>
    <s:Body>
        <s:Fault>
            <s:Code>
                <s:Value>s:Sender</s:Value>
                <s:Subcode>
                    <s:Value xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">a:InvalidSecurity</s:Value>
                </s:Subcode>
            </s:Code>
            <s:Reason>
                <s:Text xml:lang="fr-FR">Une erreur s'est produite lors de la vérification de la sécurité du message.</s:Text>
            </s:Reason>
        </s:Fault>
    </s:Body>
</s:Envelope>

抱歉文字墙,我希望清楚地了解我的问题所需的一切都在这里。 非常感谢您到目前为止的阅读 :)

编辑:如您所见,我还尝试将 header 直接放在 xml 端点中,但到目前为止没有成功。

编辑:调用绑定错误,现在是:

<binding name="WsHttpBinding_Authentication" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="Basic" />
            <message clientCredentialType="UserName" />
          </security>
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
        </binding>

有了这个新绑定,我现在的错误是:

{"globalErrors":["Message with Action 'http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT' is unknown and cannot be forwarded to the recipient. This may happen if message Action was changed, or if operation was disabled or deleted from the service contract."]}

我找不到关于此错误的内容,发生了什么:/

编辑:解决了绑定中 re-adding establishSecurityContext="false" 的错误。

编辑:要添加凭据,我正在使用 post 答案:Set WCF ClientCredentials in App.config

它似乎有效,我正在朝着一个旧错误取得进展:An error occurred when verifying security for the message.

要向服务添加用户名和密码,您需要在设置服务时执行以下操作

// Instantiate the proxy  
Service1Client proxy = new Service1Client();

// Set the user’s credentials on the proxy  
proxy.ClientCredentials.UserName.UserName = username;  
proxy.ClientCredentials.UserName.Password = password;

这是当你使用标准的 WS 用户名和密码时,我在经历了完全相同的事情后添加了我自己的问题的答案,link 是

您可以从 Microsoft

阅读更多内容

解决了!!!

非常沮丧,但是编写 SO post 并保持更新很有帮助。

我去庆祝一下,我会回来详细说明解决方案。

简而言之,使用我在编辑中添加的 link 的实现,而不是我以前的方式。