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

问题描述:

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

这是我的服务器端代码。我使用的是自定义用户名验证器,可以正常工作。我在我的机器上的IIS管理器中为默认网站>绑定配置了证书,在那里我生成了证书(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(); 

,这是关于调用service.GetCustomers()让我的客户端代码

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

: 无法与权威 为SSL信任关系/ TLS安全通道的“localhost:9000 ”。 InnerException消息: 底层连接已关闭:无法为SSL/TLS安全通道建立信任关系。 InnerException消息: 根据验证过程,远程证书无效。

当我在浏览器中测试时服务器工作正常。 但客户端代码是错误的,因为它没有去定制的证书验证器类。这个类与在http://msdn.microsoft.com/en-us/library/system.identitymodel.selectors.x509certificatevalidator.aspx上的MSDN示例中的相同。

任何人都可以请告诉我在哪里我会错用这种方法?

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

谢谢

如果你想使用WCF客户端,那么就不要使用的WebHttpBinding,坚持使用SOAP东西,它会运行得更好。
但是,如果您要使用标准HTTP客户端,如WebClientHttpWebRequest或​​3210或HttpClient V.Next,请使用webHttpBinding。

对不起,没有解决您的直接问题,但您可能会遇到更多问题,因为您使用的绑定旨在​​让WCF服务可供非WCF平台访问,但之后使用WCF尝试访问它。

+0

嗨达雷尔,感谢您的回答。我正在使用WebHttpBinding,因此我可以在移动平台上支持多种类型的客户端(即Win7,Android,iPhone)。我想先创建WinForms客户端,以了解我需要做什么。 – elector 2011-01-21 14:17:58

+0

@elector很酷。只要确保你使用标准的HTTP客户端而不是WCF频道。这样,不同平台上的客户将会更加一致地工作。 – 2011-01-21 14:28:08

+0

感谢Darrel,听起来很酷,但恐怕我不知道标准http客户端是什么意思? :)你知道c#中的例子很快吗?或者,我应该谷歌什么?正如我所说,我是新手,所以每一点信息都有很大的帮助。 – elector 2011-01-21 14:32:42

看起来像是问题发生,因为证书是针对其他主机名发布的。您可以通过提供自定义的ServicePointManager.ServerCertificateValidationCallback来检查它(并在必要时自定义)。

//不使用HttpWebRequest - 你失去了所有强类型的方法和数据契约!

//代码来创建通道并调用一个方法:

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