我正在链接到外部公司的WSDL文件,我需要用它来发送请求并通过SOAP请求收回信息。
他们提供了WSDL文件,我已将其添加为“服务参考”。通常这已经足够了,但每当我们发送请求时,我们都需要附加一个wsse头和安全性。我们设法通过添加标题来摸索我们的方式但是它有一些问题,我不太确定如何解决。
Soap Request应该看起来像:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security
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">
<wsse:UsernameToken wsu:Id="UsernameToken-17A419BD1DC95B13F214417185709617">
<wsse:Username>aUsername</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">##HashedPassword##</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">DUSgCUI8X3BJrVe8F+fGnQ==</wsse:Nonce>
<wsu:Created>2015-09-08T13:22:50.961Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<stuffhere />
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
我的请求目前看起来像;
<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>
<h:Security
xmlns:h="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<h:UsernameToken u:Id="uuid-b9edaf83-70fb-4909-85eb-9773058c7001-1" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<h:Username>aUsername</h:Username>
<h:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">##HashedPassword##</h:Password>
<h:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">kRNsqdcQdv8T5y5rTv4O2WeidUM=</h:Nonce>
<u:Created>2015-09-09T10:48:44.498Z</u:Created>
</h:UsernameToken>
</o:Security>
</s:Header>
<s:Body >
<stuffhere />
</s:Body>
</s:Envelope>
正如您所看到的,安全标签主要搞砸了。此外,XMLNS标签似乎到处都是,我不太确定这是否会导致问题。
目前我们正在使用以下课程(我从研究中得到)中超越标题;
Imports Microsoft.VisualBasic
Imports System.ServiceModel.Dispatcher
Imports System.ServiceModel.Channels
Imports System.ServiceModel
Imports System.Xml
Imports System.ServiceModel.Description
Imports System.ServiceModel.Dispatcher.ClientRuntime
Imports System
Imports System.IdentityModel.Selectors.SecurityTokenSerializer
Imports System.ServiceModel.Security
Imports System.IdentityModel.Tokens
Imports System.Security.Cryptography
Public Class CustomCredentials
Inherits ClientCredentials
Public Sub New()
End Sub
Protected Sub New(cc As CustomCredentials)
MyBase.New(cc)
End Sub
Public Overrides Function CreateSecurityTokenManager() As System.IdentityModel.Selectors.SecurityTokenManager
Return New CustomSecurityTokenManager(Me)
End Function
Protected Overrides Function CloneCore() As ClientCredentials
Return New CustomCredentials(Me)
End Function
End Class
Public Class CustomSecurityTokenManager
Inherits ClientCredentialsSecurityTokenManager
Public Sub New(cred As CustomCredentials)
MyBase.New(cred)
End Sub
Public Overrides Function CreateSecurityTokenSerializer(version As System.IdentityModel.Selectors.SecurityTokenVersion) As System.IdentityModel.Selectors.SecurityTokenSerializer
Return New CustomTokenSerializer(System.ServiceModel.Security.SecurityVersion.WSSecurity11)
End Function
End Class
Public Class CustomTokenSerializer
Inherits WSSecurityTokenSerializer
Public Sub New(sv As SecurityVersion)
MyBase.New(sv)
End Sub
'Protected Overrides Sub WriteKeyIdentifierClauseCore(writer As XmlWriter, keyIdentifierClause As SecurityKeyIdentifierClause)
' MyBase.WriteKeyIdentifierClauseCore(writer, keyIdentifierClause)
' writer.WriteRaw("TestClause")
'End Sub
Protected Overrides Sub WriteTokenCore(writer As System.Xml.XmlWriter, token As System.IdentityModel.Tokens.SecurityToken)
Dim userToken As UserNameSecurityToken = TryCast(token, UserNameSecurityToken)
Dim tokennamespace As String = "h"
Dim created As DateTime = DateTime.Now
Dim createdStr As String = created.ToString("yyyy-MM-ddThh:mm:ss.fffZ")
' unique Nonce value - encode with SHA-1 for 'randomness'
' in theory the nonce could just be the GUID by itself
Dim phrase As String = Guid.NewGuid().ToString()
Dim nonce = GetSHA1String(phrase)
' in this case password is plain text
' for digest mode password needs to be encoded as:
' PasswordAsDigest = Base64(SHA-1(Nonce + Created + Password))
' and profile needs to change to
'string password = GetSHA1String(nonce + createdStr + userToken.Password);
Dim password As String = GetSHA1String(nonce + createdStr + GetSHA1String(userToken.Password))
writer.WriteRaw(String.Format((Convert.ToString((Convert.ToString((Convert.ToString("<{0}:UsernameToken u:Id=""" + token.Id + """ xmlns:u=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"">" + "<{0}:Username>" + userToken.UserName + "</{0}:Username>" + "<{0}:Password Type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"">") & password) + "</{0}:Password>" + "<{0}:Nonce EncodingType=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"">") & nonce) + "</{0}:Nonce>" + "<u:Created>") & createdStr) + "</u:Created></{0}:UsernameToken>", tokennamespace))
End Sub
Protected Function GetSHA1String(phrase As String) As String
Dim sha1Hasher As New SHA1CryptoServiceProvider()
Dim hashedDataBytes As Byte() = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase))
Return Convert.ToBase64String(hashedDataBytes)
End Function
End Class
我的web.config目前配置为;
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="shippingAPISoapBinding">
<!--<security mode="TransportWithMessageCredential">-->
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
<transport clientCredentialType="Certificate"></transport>
</security>
</binding>
<binding name="shippingAPISoapBinding1"/>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://www.anEndpoint.com/endpoint" binding="basicHttpBinding" bindingConfiguration="shippingAPISoapBinding" contract="RMailAPI.shippingAPIPortType" name="shippingAPISoapBinding" behaviorConfiguration="ClientCertificateBehavior" >
</endpoint>
</client>
</system.serviceModel>
如前所述,我们使用wsdl发送请求,执行以下操作;
'The securityheader we have to attach to be able to call createshipmentrequest1
'The only things i can access on this are .Any or .AnyAttr which are XML attributes
Dim securityHeader As New RMailAPI.SecurityHeaderType
'We declare our requests here
Dim cs As RMailAPI.createShipmentRequest
cs = New RMailAPI.createShipmentRequest
'assign values to cs here
'These come through into the XML just fine
Dim cs1 As New RMailAPI.createShipmentRequest1(securityHeader, cs)
Try
shipResponse = serviceClient.createShipment(cs1)
Catch ex As CommunicationException
Response.Write("msg:" & ex.Message & "<br />")
End Try
如果这令人困惑,我很抱歉,我发现这整个方法非常复杂,我很确定我在这里遗漏了一些非常明显的东西。
我很乐意提供更多信息。
*编辑1;
我尝试将我的标题添加到web.config中,但是该方法存在问题,因为我的密码需要在使用随机字符串发送之前进行哈希处理(“nonce”,我还需要通过)。不确定如果我可以在发送之前更改web.config标头。
*编辑2;
一直在寻找是否有某些方法可以获得整个标头,或者我是否可以采用与“WriteTokenCore”函数相同的方式拦截它。无济于事!