2011-04-20 106 views
13

我的问题与此类似。 How To Pass Soap Header When WSDL Doesn't Define It?但是不同。将SOAP隐式标头添加到WSDL

对于我使用的Web服务,所有方法都需要在SOAP标头内以明文形式发送的身份验证。但是,我的WSDL不包含任何soap头信息。我有一个自定义的平台工具,我必须使用它来从WSDL生成代码。由于标题信息不可用,我无法直接使用生成的类 - 我不想手动修改代码以容纳标题。

我试过在WSDL中指定SOAP头,但是我没有得到正确的名称空间。该WSDL是这里https://stage.totalcheck.sensis.com.au/service/webservice?wsdl和SOAP头如下:

<soapenv:Header> 
     <wsse:Security> 
      <wsse:UsernameToken> 
       <wsse:Username>username</wsse:Username> 
       <wsse:Password>password</wsse:Password> 
      </wsse:UsernameToken> 
     </wsse:Security> 
    </soapenv:Header> 

有人能帮助我吗?谢谢!

+0

'wsse'看起来像通常用于WS-Security的前缀。另外,由于SOAP服务是自描述的,因此我无法找到WSDL中未定义头的有效原因。 – 2011-04-20 14:24:21

+0

这很好。但就像我说的,我不想触摸自动生成的类。我只是修改这个只是为了生成类。 – 2011-04-20 14:47:46

+2

自动生成的类是一个部分类。也许你可以将头添加到另一个类的一部分。当自动生成的文件再次生成时,它不会改变。 – 2011-04-20 14:57:23

回答

18

从概念的角度来看,WSDL不应该定义标题。 WSDL仅用于定义服务的功能方面,如操作,消息,绑定和端点。消息和绑定定义了消息的有效载荷应如何编码和格式化。

但是,SOAP消息的标题不属于有效负载。它们通常用于配置SOAP处理器的非功能属性。安全性是这样一种非功能性财产。有效载荷的功能方面不受影响。只有确保沟通是安全的,WS工具堆栈,而不是服务实现,应该照顾到这一点。

因此,缺失的部分现在是一个标准,允许将一些非功能性需求附加到WSDL服务,以便代码生成器可以自动导出需要发送和/或理解哪些头部以实现非功能性属性 - 不需要手动处理标题字段。该标准存在并被称为WS-Policy。政策通常包含一系列替代方案,这些替代方案公开了供应商和消费者应该能够满足的一组要求。当两种服务应该互相影响时,两种政策都会被采纳,并计算出所谓的“有效政策”。它定义了常见的非功能性需求。通过使用这些信息,提供者和使用者可以自行配置以添加必需的标题,如WS-Security标题。 WS-SecurityPolicy也定义了一组可以使用的策略。 WS-PolicyAttachment定义了如何将这些策略附加到WSDL。

有代码生成器可以处理WS-Policies,例如, Metro或Axis2

+2

头文件元素IS在wsdl/soap模式中定义,所以很难说它不应该被使用:http://schemas.xmlsoap.org/wsdl/soap/你当然可以使用WS-SecurityPolicy,但它很简单一个不同的,尽管更具体的规范。 – 2012-10-15 21:26:02

+3

同意,对于绑定,WSDL [指定](http://www.w3.org/TR/wsdl#_soap:header)如何将某些部分映射到SOAP标头。但是,从概念的角度来看,我认为这是一种不好的做法,因为它将WSDL与特定的绑定绑定在一起。我同意,这个问题也被要求提供特定的SOAP绑定,所以使用头部绑定可能没有问题,但使用WS-Policy是一种更合理的方式(即它表达了非功能性问题“确保请求是认证“与发送特定标头)。在前一种情况下,WS-stack已经知道该怎么做。 – vanto 2012-10-16 17:09:26

+0

尽管我仍然不同意这是“糟糕的做法”(日期可能是一个更好的评估),但我现在看到在这种情况下指向WS-SecurityPolicy是正确的,因为OP中的头文件是WS-Security 。 +1 – 2012-10-16 22:45:47

4

您可以通过装饰使用SoapHeader属性从wsdl生成的代理类中的方法,将soap头信息添加到方法调用中。

例如,当您“添加Web引用”时,wsdl.exe将为Web服务引用生成客户端代理类Reference.cs。在上面提到的链接https://stage.totalcheck.sensis.com.au/service/webservice?wsdl中,有一条消息suggestAddress,它会在您从Visual Studio添加Web引用时转换为生成的reference.cs客户端代理代码文件中的方法。默认情况下,当这个方法被调用时,肥皂包中将不会有Header。要将SoapHeader添加到此请求的信封中,请将[SoapHeader(“Security”)]属性添加到R​​eference.cs生成的类中的SuggestAddress方法的顶部,其中“Security”是从SoapHeader基类继承的类。

举例上述要求的安全SOAPHEADER您将创建以下类,

public partial class Security : SoapHeader 
{ 
    public UserNameToken UserNameToken { get; set; } 
} 

public partial class UserNameToken 
{ 
    public string UserName { get; set; } 
    public string Password { get; set; } 
} 

那么你将装饰在reference.cs的SuggestAddress方法类似其次,

[SoapHeader("Security")] 
public suggestAddressesResult suggestAddresses([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] addressSearch search) { 
     object[] results = this.Invoke("suggestAddresses", new object[] {search}); 
     return ((suggestAddressesResult)(results[0])); 
    } 

这将确保当调用方法suggestAddress时创建的每个信封都包含一个看起来像上面提到的安全标头,

<soapenv:Header> 
    <wsse:Security> 
     <wsse:UsernameToken> 
      <wsse:Username>username</wsse:Username> 
      <wsse:Password>password</wsse:Password> 
     </wsse:UsernameToken> 
    </wsse:Security> 
在利用这个问题来帮助自己也承认(如一些人士指出)有问题的标题是那些WS-Security标准

+0

什么是建议地址在这里提到?我不能低头。同时阻碍。我得到错误'SoapwbApp.withHeader'不包含'Invoke'的定义并且没有扩展方法'Invoke'可以被找到(接受第一个参数的类型为“SoapwbApp.withHeader”)(你是否缺少using指令或程序集引用? ) – Sagotharan 2014-10-16 06:16:31

+0

这是哪一种语言? – Marco 2015-02-04 11:25:13

1

主要适合我。

如果您的代理生成工具是“自定义”的,您可能会切换到自动为WS-Security添加标头,这似乎很合逻辑。但是,如果您使用的是WSDL.exe(Visual Studio中的“添加Web引用”),请改为使用svcutil.exe(“添加服务引用”)。

如果使用WCF代理,您可以覆盖给定的配置,并允许WCF添加标题为您提供:

<security mode="TransportWithMessageCredential"> 
    <transport clientCredentialType="None" proxyCredentialType="None" realm="" /> 
    <message clientCredentialType="UserName" algorithmSuite="Default" /> 
</security> 

从那里你可以指定密码:

RemoteSvcProxy.TheirClient client = new RemoteSvcProxy.TheirClient(); 
client.ClientCredentials.UserName.UserName = "uname"; 
client.ClientCredentials.UserName.Password = "pwd"; 

我不知道你的定制工具是什么,但也许它所基于的框架也有类似的配置选项。