WCF,REST,SSL,客户端,自定义证书验证

问题描述:

我有一个无法解决的特定问题.让我详细解释.我是这项技术的新手,所以我可能使用了一些错误的术语.如果您不明白,请更正并解释或要求解释. 我正在创建一个自托管的WCF REST服务器,该服务器托管在WPF应用程序中.它使用带有WebHttpSecurityMode.Transport的https,SLL.我正在使用自己生成的证书. 我想创建一个将使用此服务的WinForms客户端.服务器的响应格式为JSON. 我想使用继承自X509CertificateValidator的自定义验证器在客户端上验证证书.

I have a specific problem that I can't solve. Let me explain in detail. I'm new to this technology so I might be using some wrong terms. Please correct and explain or ask for explanation if you don't understand. I am creating a self hosted WCF REST server, hosted in WPF application. It uses https, SLL with WebHttpSecurityMode.Transport. I am using my own generated certificate. I would like to create a WinForms client that would use this service. The format of the response form the server is JSON. I would like to validate the certificate on the client with my custom validator inherited from X509CertificateValidator.

这是我的服务器端代码.我使用的自定义用户名验证器运行正常.我已经在我的计算机上的IIS管理器中为默认网站>绑定配置了证书,在该网站中,我已经生成了证书(Windows 7).

This is my server side code. I'm using a custom username validator that works fine. I have configured the certificate in the IIS Manager on my machine for the Default Website > Bindings, where I have generated the certificate (Windows 7).

WebServiceHost sh = new WebServiceHost(typeof(ReachService)); 
string uri = "https://localhost:9000/Service"; 
WebHttpBinding wb = new WebHttpBinding(); 
wb.Security.Mode = WebHttpSecurityMode.Transport; 
wb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
sh.AddServiceEndpoint(typeof(IReachService), wb, uri);
sh.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();
sh.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;

sh.Open();

这是我的客户代码

Uri uri = new Uri("https://localhost:9000/Service");
WebChannelFactory<ReachService> cf = new WebChannelFactory<IReachService>(uri);
WebHttpBinding wb = cf.Endpoint.Binding as WebHttpBinding;
wb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
wb.Security.Mode = WebHttpSecurityMode.Transport;
cf.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
cf.Credentials.ServiceCertificate.Authentication.CustomCertificateValidator = new CustomCertificateValidator("PL2"); // this is the name that issued the certificate
cf.Credentials.UserName.UserName = "user1"; 
cf.Credentials.UserName.Password = "user1";
IReachService service = cf.CreateChannel();
try
{
  CustomersList auth = service.GetCustomers();
}
catch (Exception ex)
{
   throw new Exception(ex.Message);
}

在致电service.GetCustomers()上,我得到: 无法使用权​​限建立SSL/TLS安全通道的信任关系 '本地主机:9000'. InnerException消息: 基础连接已关闭:无法为SSL/TLS安全通道建立信任关系. InnerException消息: 根据验证步骤,远程证书无效.

on calling service.GetCustomers() I get: Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost:9000'. InnerException Message: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. InnerException Message: The remote certificate is invalid according to the validation procedure.

在浏览器中测试时,服务器工作正常. 但是客户端代码是错误的,因为它没有转到自定义证书验证器类.此类与 http上的MSDN示例相同://msdn.microsoft.com/zh-CN/library/system.identitymodel.selectors.x509certificatevalidator.aspx .

The server is working fine when I test in the browser. But the client code is wrong cause it doesn't go to the custom cert validator class. And this class is the same as in the MSDN example on http://msdn.microsoft.com/en-us/library/system.identitymodel.selectors.x509certificatevalidator.aspx.

有人可以告诉我这种方法在哪里出问题吗?

Can anyone please tell me where am I going wrong with this approach?

如果您需要更多信息,请询问.

If you need more info please ask.

谢谢

///不使用HttpWebRequest -您将丢失所有强类型方法和数据协定!

//don't use HttpWebRequest --you lose all of the strongly-typed method and data contracts!

//创建通道并调用方法的代码:

//the code to create the channel and call a method:

SetCertPolicy(); 
var cf1 = new WebChannelFactory<TService>(new Uri(remoteServiceAddressSecure));
var service = cf1.CreateChannel();
sevice.DoMethod();

protected static void SetCertPolicy()
        {
            ServicePointManager.ServerCertificateValidationCallback += RemoteCertValidate;
        }

private static bool RemoteCertValidate(object sender, X509Certificate cert, X509Chain chain,
                SslPolicyErrors error)
        {
            // trust any cert!!!
            return true;
        }