C# 对如何创建 SOAP <wsse:Security> 头一无所知

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/734355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:06:11  来源:igfitidea点击:

Clueless about how to create SOAP <wsse:Security> header

c#.netsoap

提问by Sergej Andrejev

I'm have near to none experience with SOAP protocol. The service I need to connect to required header. I think this is somewhat standard in Java but in C# one must create this header by hand.

我几乎没有使用 SOAP 协议的经验。我需要连接到所需标头的服务。我认为这在 Java 中有些标准,但在 C# 中必须手动创建此标头。

Does anyone here been able to connect to similar service: have created the header or maybe even know about some standard library which would simplify creation of header? Can you share some code or references?

这里有没有人能够连接到类似的服务:已经创建了标头,或者甚至知道一些可以简化标头创建的标准库?你能分享一些代码或参考吗?

I also found a clue that maybe header will be generated if using WS2005, because there is WS3 addin for it. Can anybody comment this? After quick look at this addin I found simmilar fields as in Security header, but still wasn't able to create the header.

我还发现了一个线索,如果使用 WS2005,可能会生成标题,因为它有 WS3 插件。有人可以评论这个吗?快速查看此插件后,我发现与 Security 标头中的字段类似,但仍然无法创建标头。

回答by Jon Skeet

Funny you should mention that - I've been doing exactlythat recently.

有趣的你应该提到的是-我一直在做的正是最近。

I've managed to do it using a SoapExtensionwhich uses ChainStreamto keep a copy of the original stream, just copies the stream during BeforeDeserializeand adds the header during AfterSerialize.

我设法使用 a 来完成它SoapExtension,它ChainStream用于保留原始流的副本,只是在期间复制流BeforeDeserialize并在AfterSerialize.

Adding the header is a case of reading the contents of the "new" stream (returned from ChainStream) into an XML document (XDocumentin my case), adding the header, and then writing it to the original stream passed into ChainStream.

添加标头是将“新”流(从 返回ChainStream)的内容读入 XML 文档(XDocument在我的例子中),添加标头,然后将其写入传递到ChainStream.

Unfortunately this is pretty dirty, and you can't (as far as I'm aware) use a new instance with appropriate authentication information when you need to.

不幸的是,这很脏,并且您不能(据我所知)在需要时使用具有适当身份验证信息的新实例。

I've got mostof the way using a SoapHeaderinstead, adding an appropriate attribute to each method of the web service and also an appropriate field/property with an instance of the required header - but the SOAP serialization is currently giving me headaches in terms of specifying the right element names (with namespaces). It's something I've been planning to ask others about when I get the time.

我已经获得了大部分使用 a 的SoapHeader方法,为 Web 服务的每个方法添加了一个适当的属性,并添加了一个具有所需标头实例的适当字段/属性 - 但 SOAP 序列化目前让我很头疼指定正确的元素名称(带有命名空间)。这是我一直计划在我有时间的时候问其他人的事情。

Sorry not to be able to give you a full answer - and also apologies for the lack of code, it belonging to the company rather than me - but hopefully it'll at least give you a starting point.

很抱歉不能给你一个完整的答案——也很抱歉缺少代码,它属于公司而不是我——但希望它至少能给你一个起点。

回答by sipwiz

it's generally very easy to add a SOAP header to your web serivce proxy in .Net. Here's a quick code sample.

在 .Net 中将 SOAP 标头添加到您的 Web 服务代理通常非常容易。这是一个快速代码示例。

Create a new SOAP header

创建一个新的 SOAP 标头

using System.Web.Services.Protocols;

public class SoapAuthHeader : SoapHeader
{
public string Username;
public string Password;
}

In your web service proxy class:

在您的 Web 服务代理类中:

public class MyWebServicesProxy : System.Web.Services.Protocols.SoapHttpClientProtocol {

    public SoapAuthHeader AuthHeader;

    ...

}

And then to use:

然后使用:

SoapAuthHeader authHeader = new SoapAuthHeader();
authHeader.Username = "username";
authHeader.Password = "password";

MyWebServicesProxy myProxy = new MyWebServicesProxy();
myProxy.AuthHeader = authHeader;

Edit: There are other ways to this and Microsoft do have a WSE librarythat includes WS-Security taht gives much more functionality then the simple sample above. If you need Kerberos tokens or certificate signing in your SOAP header then it's the way to go. if you jsut need to add a simple username and password for a web service operating over SSL then the exmaple may be all you need.

编辑:还有其他方法可以做到这一点,微软确实有一个WSE 库,其中包含 WS-Security taht 提供了比上面的简单示例更多的功能。如果您需要在 SOAP 标头中使用 Kerberos 令牌或证书签名,那么这就是您要走的路。如果您需要为通过 SSL 运行的 Web 服务添加一个简单的用户名和密码,那么您可能只需要这个例子。

Edit: Quick blurb on WSEEarlier this decade when web services were going to take over the World a bunch of industry players (Microsoft, IBM, Sun etc.) got together to come up with standard ways of doing things over them. The body formed was OASIS. Since then Microsoft has released a number of versions of its WSE library to support some of the specifications but interestingly they've never been incorporated into the .Net framework even though the first version was made public around 2003.

编辑:WSE 上的简短介绍本十年早些时候,当 Web 服务将接管世界时,一群行业参与者(Microsoft、IBM、Sun 等)聚在一起想出了通过它们做事的标准方法。形成的身体是绿洲。从那时起,Microsoft 发布了其 WSE 库的多个版本以支持某些规范,但有趣的是,它们从未被纳入 .Net 框架,即使第一个版本在 2003 年左右公开。

Web services while still very popular and in my opinion a great way to integrate between different internet applications have gone a bit out of favour. One of the reasons is undoubtedly because AJAX and web services weren't the best of bed fellows, although that has improved. Web services also get pretty complicated once you start including all the additional sWSE specs and one of the thinge web services was suppossed to solve was the complexity in other RPC protocols, CORBA etc. In the meantime REST has gained a lot of popularity at the expense of Web Services and AJAX libraries often prefer it.

Web 服务虽然仍然非常流行,但在我看来,一种在不同 Internet 应用程序之间集成的好方法已经有点不受欢迎了。原因之一无疑是因为 AJAX 和 Web 服务并不是最好的床伴,尽管这已经有所改善。一旦您开始包含所有额外的 sWSE 规范,Web 服务也会变得非常复杂,并且 Web 服务应该解决的问题之一是其他 RPC 协议、CORBA 等的复杂性。与此同时,REST 以牺牲为代价获得了很多普及的 Web 服务和 AJAX 库通常更喜欢它。

Web services aren't going to disappear soon by any means but they're probably not going to take over the World anytime soon either.

Web 服务无论如何都不会很快消失,但它们也可能不会很快接管世界。

回答by K Man

There is an open source custom Binding called ClearUserNameBinding, this binding helps passing UserNameToken as clearText on Http. This helped me out when a java based web service needed to be consumed using a WCF cllient.

有一个名为 ClearUserNameBinding 的开源自定义绑定,此绑定有助于在 Http 上将 UserNameToken 作为 clearText 传递。当需要使用 WCF 客户端使用基于 Java 的 Web 服务时,这帮助了我。

http://code.google.com/p/wcf-clear-username-binding/http://webservices20.blogspot.com/2008/11/introducing-wcf-clearusernamebinding.html

http://code.google.com/p/wcf-clear-username-binding/ http://webservices20.blogspot.com/2008/11/introducing-wcf-clearusernamebinding.html

回答by David

We were able to solve it with the following code:

我们能够使用以下代码解决它:

public class SecurityHeader : System.ServiceModel.Channels.MessageHeader {
    public string userName;
    public string password;

    protected override void OnWriteStartHeader (System.Xml.XmlDictionaryWriter writer, System.ServiceModel.Channels.MessageVersion messageVersion)
    {
        writer.WriteStartElement("wsse", Name, Namespace);
        writer.WriteXmlnsAttribute("wsse", Namespace);
    }

    protected override void OnWriteHeaderContents (System.Xml.XmlDictionaryWriter writer, System.ServiceModel.Channels.MessageVersion messageVersion)
    {
        writer.WriteStartElement("wsse", "UsernameToken", Namespace);

        writer.WriteStartElement("wsse", "Username", Namespace);
        writer.WriteValue(userName);
        writer.WriteEndElement();

        writer.WriteStartElement("wsse", "Password", Namespace);
        writer.WriteValue(password);
        writer.WriteEndElement();

        writer.WriteEndElement();

    }

    public override string Name
    {
        get { return "Security"; }
    }

    public override string Namespace
    {
        get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
    }
}

This wrote the header that was required by the DataPower box.

这编写了 DataPower 框所需的标头。

How to use the class SecurityHeader

如何使用 SecurityHeader 类

    public static void Main(string[] args)
    {

        var webService = new ServiceReference1.MyWebService();
        ....
       webService.Open();


        using (OperationContextScope scope = new OperationContextScope((IContextChannel)webService.InnerChannel))
        {

            var myObjRequest = GetMyObjRequest();

            MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;
            messageHeadersElement.Add(SecurityHeader("UserName", "Password"))


             var res = webService.MyServe(myObjRequest);
            Console.WriteLine(res.ToString());
        }
    }

回答by Nazir A

Solution by Domenico Zinziworked for me with below amendments: I created a constructor in SecurityHeader Class:

Domenico Zinzi 的解决方案为我工作,并进行了以下修改:我在 SecurityHeader 类中创建了一个构造函数:

public SecurityHeader(string userName, string password){ userName = userName; password = password; }

public SecurityHeader(string userName, string password){ userName = userName; password = password; }

and while calling it I used "New" keyword, as mentioned below:

在调用它时,我使用了“New”关键字,如下所述:

messageHeadersElement.Add(New SecurityHeader("UserName", "Password"))

messageHeadersElement.Add(New SecurityHeader("UserName", "Password"))

And it worked :)

它奏效了:)

P.S. Not able to add this as comments thats why adding it here.

PS 无法将其添加为评论,这就是为什么在此处添加它。