8

我已经阅读了很多文章和答案,但我无法解决。

我在我的项目中使用 .NET Framework 4.0。因此,我首先将 WebService 添加为服务引用并在我的 app.config 上获取绑定。我将列出我的尝试


尝试#1

我像这样实例化了服务并添加了凭据:

在 App.Config 上

<binding name="SubscriptionWSImplServiceSoapBinding" >
  <security mode="TransportWithMessageCredential">
    <transport clientCredentialType="Basic"/>
  </security>
</binding>

SubscriptionWSImplServiceClient ClientWs = new SubscriptionWSImplServiceClient();
ClientWs.ClientCredentials.UserName.UserName = "some-username";
ClientWs.ClientCredentials.UserName.Password = "some-password";

var SomeResposne = ClientWs.RunMethod(); //I have exception at this point

我得到一个异常如下:

 System.ArgumentException: The provided URI scheme 'http' is invalid;
 expected 'https'. Parameter name: via at System.ServiceModel.Channels

例外情况是 Web 服务的 url 必须是 HTTPS,但给我的 Web 服务 url 是 HTTP 而不是 HTTPS。

但我不介意 HttpS 并进行了第二次尝试。


尝试#2

this answer所述, 我尝试如下:

BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
CustomBinding customBinding = new CustomBinding(binding);
SecurityBindingElement element = customBinding.Elements.Find<SecurityBindingElement>();
element.IncludeTimestamp = false;

EndpointAddress address = new EndpointAddress("https://www.GivenServiceUrl.com/WebService"); //Note that the url does not end as ..svc or ..asmx! Just the name like this with no dot or extension


SubscriptionWSImplServiceClient ClientWs = new SubscriptionWSImplService(customBinding, address);
ClientWs.ClientCredentials.UserName.UserName = "some-username";
ClientWs.ClientCredentials.UserName.Password = "some-password";

var SomeResposne = ClientWs.RunMethod(); //I have exception at this point

我得到一个异常如下:

System.ServiceModel.Security.SecurityNegotiationException:无法为具有权限“ https://www.GivenServiceUrl.com/WebService ”的 SSL/TLS 安全通道建立信任关系

因此,我进行了第三次尝试,我在我的项目中将参考作为 WebReference 而不是作为 ServiceReference。


尝试#3

SubscriptionWSImplService ClientWs2 = new SubscriptionWSImplService();
var SomeResposne = ClientWs.RunMethod(); //I have exception at this point

我现在不知道如何发送安全标头。

我得到一个异常如下:

 System.Web.Services.Protocols.SoapHeaderException: An error was
 discovered processing the <wsse: Security> header

但是在这里,我无法添加必要的标题。你能帮我解决这个问题吗?


Attempt 1 或 Attempt 2 或 Attempt 3,考虑到我使用的是 Framework 4.0,应该使用哪一个?我该如何解决这个问题?

根据文档,最终请求 SOAP 必须如下所示:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sub="http://subscription.services.ws.fourplay.com.tr/">
   <soapenv:Header>
      <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
         <wsse:UsernameToken wsu:Id="UsernameToken-12" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:Username>admin</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">123456</wsse:Password>
           <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">1lcj+WbCMlrPyhcud4QxiQ==</wsse:Nonce>
           <wsu:Created>2012-06-05T10:23:26.879Z</wsu:Created>
        </wsse:UsernameToken>
     </wsse:Security>
   </soapenv:Header>
   <soapenv:Body>
      <sub:RunMethod>
         <!--Optional:-->
         <sub:opaque id>555555555</sub:opaque id>
         <sub:params>
            <!--Optional:-->
            <name>GUID</name>
            <!--Optional:-->
            <value>2fc4ce1d-645e-41f4-811e-28510a02a17f </value>
         </sub:params>      
</sub: RunMethod >
4

3 回答 3

8

我通过使用没有声明任何凭据的 WCF 解决了它。我通过构建我的自定义标题来做到这一点我从这个链接获得了帮助

public class SoapSecurityHeader : MessageHeader
    {
        private readonly string _password, _username, _nonce;
        private readonly DateTime _createdDate;

        public SoapSecurityHeader(string id, string username, string password, string nonce)
        {
            _password = password;
            _username = username;
            _nonce = nonce;
            _createdDate = DateTime.Now;
            this.Id = id;
        }

        public string Id { get; set; }

        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"; }
        }

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

        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteStartElement("wsse", "UsernameToken", Namespace);
            writer.WriteAttributeString("Id", "UsernameToken-10");
            writer.WriteAttributeString("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

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

            writer.WriteStartElement("wsse", "Password", Namespace);
            writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
            writer.WriteValue(_password);
            writer.WriteEndElement();

            writer.WriteStartElement("wsse", "Nonce", Namespace);
            writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
            writer.WriteValue(_nonce);
            writer.WriteEndElement();

            writer.WriteStartElement("wsse", "Created", Namespace);
            writer.WriteValue(_createdDate.ToString("YYYY-MM-DDThh:mm:ss"));
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
    }

以及如何使用我从这个链接得到的标题。

于 2013-10-02T12:38:46.900 回答
3

优秀的职位。你们都救了我的命!!我必须进行一些更改才能获得以下标题:

<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xml:mustUnderstand="1">
    <wsse:UsernameToken wsu:Id="UsernameToken-15" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:Username>EFO140714JPA</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">SgBJAHMANwBBACYANQBOAG8ANwAzACEANgBrAGEAJgBIAGwAJABMAA==</wsse:Password>
        <wsse:Nonce>SgBJAHMANwBBACYANQBOAG8ANwAzACEANgBrAGEAJgBIAGwAJABMAA==</wsse:Nonce>
        <wsu:Created>2016-08-04T11:24:10.0Z</wsu:Created>
    </wsse:UsernameToken>
</wsse:Security>

我所做的更改如下:

        public class SoapSecurityHeader : MessageHeader
        {
            private readonly string _password, _username, _nonce, _createdDate;

            public SoapSecurityHeader(string id, string username, string password, string nonce, string created)
            {
                _password = password;
                _username = username;
                _nonce = nonce;
                _createdDate = created;
                this.Id = id;
            }

            public string Id { get; set; }

            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"; }
            }

            protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
            {
                writer.WriteStartElement("wsse", Name, Namespace);
                writer.WriteXmlnsAttribute("wsse", Namespace);
 ------->       writer.WriteXmlAttribute("mustUnderstand", "1");
            }


            protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
            {
                writer.WriteStartElement("wsse", "UsernameToken", Namespace);
                writer.WriteAttributeString("wsu:Id", "UsernameToken-15");
                writer.WriteAttributeString("xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

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

                writer.WriteStartElement("wsse", "Password", Namespace);
  ----->        writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest");
                writer.WriteValue(_password);
                writer.WriteEndElement();

                writer.WriteStartElement("wsse", "Nonce", Namespace);
                writer.WriteValue(_nonce);
                writer.WriteEndElement();

  ------>       writer.WriteStartElement("wsu:Created");
                writer.WriteValue(_createdDate);
                writer.WriteEndElement();

                writer.WriteEndElement();
            }
        }
于 2020-08-24T16:48:57.103 回答
3

我遇到了与问题的第一次尝试相同的问题,我需要有与问题相同的输出。答案非常好,但只是为了改进上述答案,或者我应该说将答案与链接结合起来,我做了以下操作。

 public class Security : MessageHeader
{
    private readonly string _password, _username, _nonce;
    private readonly DateTime _createdDate;

    public Security(string id, string username, string password, string nonce)
    {
        _password = password;
        _username = username;
        _nonce = nonce;
        _createdDate = DateTime.Now;
        this.Id = id;
    }

    public string Id { get; set; }

    public override string Name => "Security";

    public override string Namespace => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";

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

    protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        writer.WriteStartElement("wsse", "UsernameToken", Namespace);
        writer.WriteAttributeString("Id", "UsernameToken-10");
        writer.WriteAttributeString("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

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

        writer.WriteStartElement("wsse", "Password", Namespace);
        writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
        writer.WriteValue(_password);
        writer.WriteEndElement();

        writer.WriteStartElement("wsse", "Nonce", Namespace);
        writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
        writer.WriteValue(_nonce);
        writer.WriteEndElement();

        writer.WriteStartElement("wsse", "Created", Namespace);
        writer.WriteValue(_createdDate.ToString("YYYY-MM-DDThh:mm:ss"));
        writer.WriteEndElement();

        writer.WriteEndElement();
    }
}
/// <summary>
/// Represents a message inspector object that can be added to the <c>MessageInspectors</c> collection to view or modify messages.
/// </summary>
public class ClientMessageInspector : IClientMessageInspector
{
    /// <summary>
    /// Enables inspection or modification of a message before a request message is sent to a service.
    /// </summary>
    /// <param name="request">The message to be sent to the service.</param>
    /// <param name="channel">The WCF client object channel.</param>
    /// <returns>
    /// The object that is returned as the <paramref name="correlationState " /> argument of
    /// the <see cref="M:System.ServiceModel.Dispatcher.IClientMessageInspector.AfterReceiveReply(System.ServiceModel.Channels.Message@,System.Object)" /> method.
    /// This is null if no correlation state is used.The best practice is to make this a <see cref="T:System.Guid" /> to ensure that no two
    /// <paramref name="correlationState" /> objects are the same.
    /// </returns>
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
///enter your username and password here.
        Security header = new Security("xx", "xx", "xx!","xx");

        request.Headers.Add(header);
        return header.Name;
    }

    /// <summary>
    /// Enables inspection or modification of a message after a reply message is received but prior to passing it back to the client application.
    /// </summary>
    /// <param name="reply">The message to be transformed into types and handed back to the client application.</param>
    /// <param name="correlationState">Correlation state data.</param>
    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {

    }
}

/// <summary>
/// Represents a run-time behavior extension for a client endpoint.
/// </summary>
public class CustomEndpointBehavior : IEndpointBehavior
{
    /// <summary>
    /// Implements a modification or extension of the client across an endpoint.
    /// </summary>
    /// <param name="endpoint">The endpoint that is to be customized.</param>
    /// <param name="clientRuntime">The client runtime to be customized.</param>
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new ClientMessageInspector());
    }

    /// <summary>
    /// Implement to pass data at runtime to bindings to support custom behavior.
    /// </summary>
    /// <param name="endpoint">The endpoint to modify.</param>
    /// <param name="bindingParameters">The objects that binding elements require to support the behavior.</param>
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        // Nothing special here
    }

    /// <summary>
    /// Implements a modification or extension of the service across an endpoint.
    /// </summary>
    /// <param name="endpoint">The endpoint that exposes the contract.</param>
    /// <param name="endpointDispatcher">The endpoint dispatcher to be modified or extended.</param>
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        // Nothing special here
    }

    /// <summary>
    /// Implement to confirm that the endpoint meets some intended criteria.
    /// </summary>
    /// <param name="endpoint">The endpoint to validate.</param>
    public void Validate(ServiceEndpoint endpoint)
    {
        // Nothing special here
    }
}
于 2017-10-30T13:21:57.947 回答