将SOAP隐式标头添加到WSDL

时间:2011-04-20 05:59:25

标签: soap wsdl soapheader

我的问题与此类似。 How To Pass Soap Header When WSDL Doesn't Define It?但不同。

对于我使用的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>

有人能帮助我吗?谢谢!

3 个答案:

答案 0 :(得分:20)

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

然而,SOAP消息的头部不属于有效负载。它们通常用于配置SOAP处理器的非功能属性。安全是一种非功能性的财产。有效载荷的功能方面不受影响。只保证通信是安全的,WS工具堆栈而不是服务实现应该解决这个问题。

因此,缺少的部分现在是一个标准,允许将一些非功能性需求附加到WSDL服务,以便代码生成器可以自动派生需要发送和/或理解的头,以实现非功能属性根据需要 - 无需手动处理标题字段。该标准存在并称为WS-Policy。策略通常包含一组备选方案,这些方案公开了提供者和消费者都应该能够实现的一组要求。当两个服务相互交互时,采取两种策略并计算所谓的“有效策略”。它定义了常见的非功能性需求。使用此信息,提供者和使用者可以自行配置以添加所需的标头,例如WS-Security标头。 WS-SecurityPolicy还定义了一组可以使用的策略。 WS-PolicyAttachment定义了如何将这些策略附加到WSDL。

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

答案 1 :(得分: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客户端代理代码文件中的方法。默认情况下,调用此方法时,soap信封中不会包含Header。要将SoapHeader添加到此请求的信封中,请在Reference.cs生成的类的SuggestAddress方法的顶部添加[SoapHeader(“Security”)]属性,其中“Security”是继承自SoapHeader基类的类。

上面要求的Security 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>

答案 2 :(得分:1)

使用这个问题帮我自己的关键是认识到(正如一些人指出的那样)所讨论的标题是WS-Security标准的标题。

如果您的代理生成工具是“自定义”,那么您可能需要切换到自动添加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";

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