我正在尝试通过其相应的wsdl使用Web服务。此服务依赖于符合Web服务安全基本安全配置文件1.0的身份验证,包括http://docs.oasis- open.org/wss/2004/01/oasis-200401wss-wssecurity-secext-1.0的正确xmls命名空间。 xsd必须包含在请求中。
例:
<wsse:UsernameToken xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' > <wsse:Username> Bob </wsse:Username> <wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'> 1234 </wsse:Password> </wsse:UsernameToken>
我的最初尝试是Add Service Reference针对wsdl,并从使用它们的代理生成
Add Service Reference
ServicePointManager.ServerCertificateValidationCallback = (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => true; var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; var endpoint = new EndpointAddress("https://secure-ausomxana.crmondemand.com/..." using (var client = new ContactClient(basicHttpBinding, endpoint)) { var credential = client.ClientCredentials.UserName; credential.UserName = "bob"; credential.Password = "1234"; var input = ... var output = client.ContactQueryPage(input); }
但是,尝试用Fiddler询问SOAP消息时,我发现没有添加UsernameToken元素。
履行此合同的正确方法是什么?
编辑: 根据来自@John Saunders的响应,我尝试更改我的代码以使用wsHttpBinding
var wsHttpBinding = new WSHttpBinding(SecurityMode.Transport); wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
使用此绑定,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">document/urn:crmondemand/ws/ecbs/contact/10/2004:ContactQueryPage</a:Action> <a:MessageID>urn:uuid:17807f44-1fcasfdsfd</a:MessageID> <a:ReplyTo> <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> </a:ReplyTo> <a:To s:mustUnderstand="1">https://secure-ausomxana.crmondemand.com/Services/Integration</a:To> </s:Header> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ContactQueryPage_Input xmlns="urn:crmondemand/ws/ecbs/contact/10/2004"> <ListOfContact xmlns="urn:/crmondemand/xml/Contact/Query"> <Contact> <Id>1-asdfd</Id> </Contact> </ListOfContact> </ContactQueryPage_Input> </s:Body> </s:Envelope>
这将添加Header元素,与wsse:UsernameToken使用BasicHttpBinding引用原始肥皂消息的元素相反,它是
wsse:UsernameToken
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ContactQueryPage_Input xmlns="urn:crmondemand/ws/ecbs/contact/10/2004"> <ListOfContact xmlns="urn:/crmondemand/xml/Contact/Query"> <Contact> <Id>1-asdfds</Id> </Contact> </ListOfContact> </ContactQueryPage_Input> </s:Body> </s:Envelope>
如果我将绑定更改为
var wsHttpBinding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential); wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
我得到的SOAP消息是
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <s:Header> <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</a:Action> <a:MessageID>urn:uuid:eeb75457-f29e-4c65-b4bf-b580da26e0c5</a:MessageID> <a:ReplyTo> <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> </a:ReplyTo> <a:To s:mustUnderstand="1">https://secure-ausomxana.crmondemand.com/Services/Integration</a:To> <o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1"> <u:Timestamp u:Id="_0"> <u:Created>2011-05-02T13:30:09.360Z</u:Created> <u:Expires>2011-05-02T13:35:09.360Z</u:Expires> </u:Timestamp> <o:UsernameToken u:Id="uuid-dc3605a0-6878-42f4-b1f2-37d5c04ed7b4-2"> <o:Username>Bob</o:Username> <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">1234</o:Password> </o:UsernameToken> </o:Security> </s:Header> <s:Body> <t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"> <t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType> <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType> <t:Entropy> <t:BinarySecret u:Id="uuid-7195ad74-580b-4e52-9e2c-682e5a684345-1" Type="http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce">bI4xuyKwZ8OkQYBRnz2LDNV+zhIOnl0nwP24yI1QAwA=</t:BinarySecret> </t:Entropy> <t:KeySize>256</t:KeySize> </t:RequestSecurityToken> </s:Body> </s:Envelope>
这似乎非常接近,但是实际上似乎已经加密了肥皂消息的正文,这是我不希望发生的事情。
如果我wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;仅指定使用SecurityMode.Transport,则返回其匿名状态。
wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
SecurityMode.Transport
我无法解决的最后障碍是什么?
最终解决方案: 弄清楚我会在这种情况下对他人有所帮助的,这里没有其他区别,其他情况是UserToken对象包装在Security节点中,这是我的服务提供者所需要的,并且似乎是我先前示例中的输出如何我可以生成。
<system.serviceModel> <bindings> <basicHttpBinding> <binding name="Contact" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="524288" maxBufferPoolSize="524288" maxReceivedMessageSize="524288" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true"> <readerQuotas maxDepth="32" maxStringContentLength="65536" maxArrayLength="131072" maxBytesPerRead="32768" maxNameTableCharCount="131072" /> <security mode="Transport"> <transport clientCredentialType="None" proxyCredentialType="None" realm="" /> <message clientCredentialType="UserName" algorithmSuite="Default" /> </security> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="https://secure-ausomxana.crmondemand.com/Services/Integration" binding="basicHttpBinding" bindingConfiguration="Contact" contract="OnDemandContactService.Contact" name="OnDemand.Contact.Endpoint"> <headers> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>USERNAME</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">PASSWORD</wsse:Password> </wsse:UsernameToken> </wsse:Security> </headers> </endpoint> </client> </system.serviceModel>
请参阅使用C#,使用WSSE纯文本身份验证的WCF SOAP使用者?有关如何使用代码而不是config进行配置
如果需要通过HTTPS发送用户名,则可以使用标准方法(如果正确定义了WSDL,则应该通过添加服务引用为您自动创建):
<bindings> <basicHttpBinding> <binding name="secured"> <security mode="TransportWithMessageCredential"> <message clientCredentialType="UserName" /> </security> </binding> </basicHttpBinding> </bindings> <client> <endpoint name="..." address="https://..." contract="..." binding="basicHttpBinding" bindingConfiguration="secured" /> </client>
您可以在代码中定义绑定:
var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential); basicHttpBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
您现在将在代理中设置凭据:
client.ClientCredentials.UserName.UserName = "bob"; client.ClientCredentials.UserName.Password = "1234";
如果只需要HTTP上的UserNameToken配置文件,而没有任何其他WS- Security基础结构,则最简单的方法是使用ClearUserNameBinding。
如果您对来自客户端的所有请求都需要相同的用户名和密码,则可以使用没有任何安全性的简单basicHttpBinding并包括配置中的静态标头:
<client> <endpoint ...> <headers> <wsse:UsernameToken xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' > <wsse:Username>Bob</wsse:Username> <wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'> 1234 </wsse:Password> </wsse:UsernameToken> </headers> </endpoint> </client>
如果您需要更复杂的内容,请显示WSDL(安全性断言)的相关部分或示例SOAP请求。还要提及是否需要使用HTTP或HTTPS。