C# 使用https协议消费Web服务

C# 使用https协议消费Web服务,c#,web-services,wcf,authentication,ssl,C#,Web Services,Wcf,Authentication,Ssl,我正在开发一个应用程序,在这个应用程序中,我必须使用使用http协议在Java中开发的Web服务。 我正在使用C#.NET winforms开发应用程序。直到现在一切都很好。Web服务现在使用SSL安全性,因此服务协议从http更改为https。我在访问https Web服务时遇到问题 我尝试从SoapUI访问https Web服务,方法是从Auth选项卡提供身份验证参数(用户名和密码),如下所示: 它在SoapUI中运行良好 但是,我从代码中提供的身份验证参数如下,它不起作用: client

我正在开发一个应用程序,在这个应用程序中,我必须使用使用http协议在Java中开发的Web服务。 我正在使用C#.NET winforms开发应用程序。直到现在一切都很好。Web服务现在使用SSL安全性,因此服务协议从http更改为https。我在访问https Web服务时遇到问题

我尝试从SoapUI访问https Web服务,方法是从Auth选项卡提供身份验证参数(用户名和密码),如下所示:

它在SoapUI中运行良好

但是,我从代码中提供的身份验证参数如下,它不起作用:

client.ClientCredentials.UserName.UserName = "admin";
client.ClientCredentials.UserName.Password = "*******";
我使用的安全模式是:
TransportWithMessageCredential
clientcredentialtype
as:
Basic

我的
App.Config
文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <system.serviceModel>
    <client>
      <endpoint address="https://xyz:8001/HelloWorldAPI/HelloWorldWebService"
       binding="wsHttpBinding"
        bindingConfiguration="myhttpsbinding" contract="API.HelloWorldWebService"
        name="HelloWorldWebServicePort" />
    </client>
    <bindings>
      <wsHttpBinding>
        <binding name="myhttpsbinding">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="Basic"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>
  <system.net>
    <defaultProxy useDefaultCredentials="true" />
  </system.net>
</configuration>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using testingtool.API;

namespace testingtool
{
    class Program
    {
        static void Main(string[] args)
        {
            new APITool();
        }
    }
    class APITool
    {
        UserInfo userinfo = new UserInfo();
        HelloWorldWebServiceClient client = new HelloWorldWebServiceClient();

        private bool ValidationCallBack(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
        {
            return true;
        }

        public APITool()
        {
            try
            {
                //Authentication parameters
                client.ClientCredentials.UserName.UserName = "admin";
                client.ClientCredentials.UserName.Password = "*****";
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(ValidationCallBack);

                //client ClientCredentials @ Application level
                userinfo.userid = "myusername";
                userinfo.password = "*****";
                GetHelloWorldAPIVersionRequest request = new GetHelloWorldAPIVersionRequest();

                APIVersionInfo versioninfo = new APIVersionInfo();
                versioninfo.userinfo = userinfo;
                request.APIVersionInfo = versioninfo;


                APIVersionInfoResponse response = client.GetHelloWorldAPIVersion(versioninfo);
                Console.WriteLine(response.Version);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            Console.ReadLine();
        }
     }
  } 
CONNECT 10.10.10.110:8001 
HTTP/1.1 Host: 10.10.10.110:8001 
Connection: Keep-Alive 
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
我遇到了以下异常:

System.ServiceModel.Security.MessageSecurityException:HTTP 客户端身份验证方案“匿名”未授权请求。 从服务器接收的身份验证标头为“基本” realm=“EJBServiceEndpointServlet领域””。--> System.Net.WebException:远程服务器返回错误:(401) 未经授权

编辑:我已通过Fiddler验证了客户端的请求窗口,如下所示: 在AUth选项卡中,它表示不存在任何Authorization标头

Fiddler原始请求如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <system.serviceModel>
    <client>
      <endpoint address="https://xyz:8001/HelloWorldAPI/HelloWorldWebService"
       binding="wsHttpBinding"
        bindingConfiguration="myhttpsbinding" contract="API.HelloWorldWebService"
        name="HelloWorldWebServicePort" />
    </client>
    <bindings>
      <wsHttpBinding>
        <binding name="myhttpsbinding">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="Basic"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>
  <system.net>
    <defaultProxy useDefaultCredentials="true" />
  </system.net>
</configuration>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using testingtool.API;

namespace testingtool
{
    class Program
    {
        static void Main(string[] args)
        {
            new APITool();
        }
    }
    class APITool
    {
        UserInfo userinfo = new UserInfo();
        HelloWorldWebServiceClient client = new HelloWorldWebServiceClient();

        private bool ValidationCallBack(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
        {
            return true;
        }

        public APITool()
        {
            try
            {
                //Authentication parameters
                client.ClientCredentials.UserName.UserName = "admin";
                client.ClientCredentials.UserName.Password = "*****";
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(ValidationCallBack);

                //client ClientCredentials @ Application level
                userinfo.userid = "myusername";
                userinfo.password = "*****";
                GetHelloWorldAPIVersionRequest request = new GetHelloWorldAPIVersionRequest();

                APIVersionInfo versioninfo = new APIVersionInfo();
                versioninfo.userinfo = userinfo;
                request.APIVersionInfo = versioninfo;


                APIVersionInfoResponse response = client.GetHelloWorldAPIVersion(versioninfo);
                Console.WriteLine(response.Version);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            Console.ReadLine();
        }
     }
  } 
CONNECT 10.10.10.110:8001 
HTTP/1.1 Host: 10.10.10.110:8001 
Connection: Keep-Alive 
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

非常感谢您的帮助。

您应该更改应用程序配置:

    <wsHttpBinding>
        <binding name="myhttpsbinding">
          <security mode="TransportWithMessageCredential">
             <transport clientCredentialType="None" />
             <message clientCredentialType="UserName" establishSecurityContext="false" negotiateServiceCredential="false"/>
          </security>
        </binding>
     </wsHttpBinding>


在传输级别上,您没有身份验证,因此在消息级别上,您有用户名|密码身份验证,因此,
想知道问题是否与绑定有关,尽管在没有查看服务配置或看到成功的soapUI请求的情况下很难确定。(注意:您可能希望包含来自soapUI HTTP日志的消息片段,包括soap头。)

在任何情况下,您都可能希望通过尝试以下绑定来确保服务真正使用ws-security(消息级安全性):

<bindings>
  <basicHttpBinding>
    <binding name="httpBinding">
      <security mode="TransportCredentialOnly">
        <transport clientCredentialType="Basic" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

您要通过代理服务器吗?如果是,详细信息是否输入IE?你能在IE中浏览https页面吗?如果是,则每个进行https调用的
WebRequest
都应选择此选项,因为它需要向代理服务器发出一个请求(它正在执行),但在您的调用中,
代理授权
头丢失。这应该是你的重点-尝试一个简单的
WebRequest
说https://google.com,看看你从fiddler中得到了什么


您的代理服务器转发请求时可能出现问题。您是否可以在不在代理后面的其他网络上尝试https?

此链接可能会有所帮助

它解释了在使用REST/SOAP Web服务时如何配置端点


它的绑定问题您需要使用自定义绑定,这里就是一个例子

我已经给出了
内部绑定,并解决了调用HTTPS服务的问题。完整代码:

<system.serviceModel>
    <bindings>
      <basicHttpBinding>       
        <binding name="ServiceSoap">
            <security mode="Transport" />
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>      
      <endpoint address="https://yourlink/Service.asmx" binding="basicHttpBinding" bindingConfiguration="ServiceSoap" contract="EmployeeService.ServiceSoap" name="ServiceSoap"/>
    </client>
  </system.serviceModel>


您能否在服务器上确认请求是以HTTPS的形式传入的?也许使用Fiddler,您可以提取实际发送的消息。感谢您的回复,从客户端我尝试使用Fiddler,我得到401错误。请查看我编辑的帖子。因此,如果我理解正确,我们清楚这是客户端问题?这排除了服务器端。@PatrickHofman:好的,谢谢,现在请你指导我解决这个问题。既然你可以从SOAPUI访问服务,你能用FiddlerTanks将来自SOAPUI的原始请求与来自客户端应用程序的原始请求进行比较吗,但是现在我得到了以下异常
System.ServiceModel.Security.MessageSecurityException:HTTP请求未经客户端身份验证方案“匿名”授权。从服务器接收的身份验证标头为“Basic realm=“EJBServiceEndpointServlet realm””。-->System.Net.WebException:远程服务器返回了一个错误:(401)未经授权。
但是当我从
SOAP UI
提供身份验证属性(用户名和密码)时,它工作正常。我想我一定缺少一些非常基本的内容。你确定这个错误不是来自应用程序级别(userinfo.userid=“myusername”吗;userinfo.password=“****”)?是的,我确信错误不是来自应用程序级别,因为当我使用与
http
url相同的凭据时,它工作正常。此标记在配置中的用途是什么?你有代理吗?如果否,请删除此标记,如果是,则应该有代理地址