生龙活虎1986

导航

WCF的https安全(ssl)访问实例

近来用WCF应用的时候,需要部署到IIS以https的安全连接访问

虽然网上此类教程不少.但我还是郁闷了很久..主要是小问题..在此写下.以免大家犯同样的错误

下面看 我一步一步做..(注:以下所有工程都得引用:System.ServiceModel)

首先用VS建个网站和一个接口工程:testhttpswcf   ,   testhttpswcf.IServer

在工程testhttpswcf.IServer中添加一个接口:IService1.cs
代码如下:

折叠
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.ServiceModel;  
  5. using System.Text;  
  6.   
  7. namespace testhttpswcf  
  8. {  
  9.     // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。  
  10.     [ServiceContract]  
  11.     public interface IService1  
  12.     {  
  13.         [OperationContract]  
  14.         string DoWork(string s);  
  15.     }  
  16. }  

网站:testhttpswcf   引用此接口工程,并建一个WCF服务.让其实现上面的接口
如下代码:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Runtime.Serialization;  
  5. using System.ServiceModel;  
  6. using System.Text;  
  7. using System.ServiceModel.Activation;  
  8.   
  9. namespace testhttpswcf  
  10. {  
  11.     // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。  
  12.     [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]  
  13.     public class Service1 : IService1  
  14.     {  
  15.         public string DoWork(string s)  
  16.         {  
  17.             return "您输入了:"+s;  
  18.         }  
  19.     }  
  20. }  


下面是配置WCF服务,打开服务网站的web.config
添加节点如下:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <!--  
  4.   有关如何配置 ASP.NET 应用程序的详细消息,请访问  
  5.   http://go.microsoft.com/fwlink/?LinkId=169433  
  6.   -->  
  7.   
  8. <configuration>  
  9.     <system.web>  
  10.         <compilation debug="true" targetFramework="4.0" />  
  11.     </system.web>  
  12.   
  13.     <system.serviceModel>  
  14.         <bindings>  
  15.             <wsHttpBinding>  
  16.                 <binding name="AllBindingConfiguration">  
  17.                     <security mode="Transport">  
  18.                         <transport clientCredentialType="None" />  
  19.                     </security>  
  20.                 </binding>  
  21.             </wsHttpBinding>  
  22.         </bindings>  
  23.         <client />  
  24.         <behaviors>  
  25.             <serviceBehaviors>  
  26.                 <behavior name="AllbehaviorConfiguration">  
  27.                     <serviceMetadata httpsGetEnabled="true" />  
  28.                     <serviceDebug includeExceptionDetailInFaults="false" />  
  29.                 </behavior>  
  30.             </serviceBehaviors>  
  31.         </behaviors>  
  32.         <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />  
  33.   
  34.       <services>  
  35.         <service name="testhttpswcf.Service1" behaviorConfiguration="AllbehaviorConfiguration">            
  36.           <endpoint address=""  binding="wsHttpBinding" contract="testhttpswcf.IService1"  
  37. bindingConfiguration="AllBindingConfiguration"  >             
  38.           </endpoint>           
  39.           <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>  
  40.         </service>  
  41.       </services>  
  42.   
  43.     </system.serviceModel>  
  44. </configuration>  

以上配置需要注意的地方:

1.<security mode="Transport">必须配置.
2.<serviceMetadata httpsGetEnabled="true" />这里的httpsGetEnabled要注意加s,不是httpGetEnabled
3.<service name="testhttpswcf.Service1" behaviorConfiguration="AllbehaviorConfiguration">   中的name必须是服务SVC的空间加上类名.不能写成接口.testhttpswcf.IService1.
[有零个应用程序(非基础结构)终结点,就有可能是此错误]
而<endpoint address=""  binding="wsHttpBinding" contract="testhttpswcf.IService1"  bindingConfiguration="AllBindingConfiguration"  >           

          </endpoint>    中的contract接须是接口.

bindingConfiguration得配置为上面的binding节点的name:如:<wsHttpBinding>

                <binding name="AllBindingConfiguration">中的AllBindingConfiguration

behaviorConfiguration配置为上面的behavior的name:<behavior name="AllbehaviorConfiguration">中的AllbehaviorConfiguration


服务配置好了..把它发布到IIS中.建一个叫wcf的网站;
至于iis的https设置请查看另一篇:www.jiamaocode.com/Conts/2010/09/28/1264/1264.html    


要保证输入网址可以得到如下效果:https


这里也要注意..选中WCF网站..把设置为必须通过https访问..不然没有意义.



到此服务已经部署完成.下面来接怎么调用

在刚才的项目中添加一个控制台工程.testClient.并引用刚才那个服务的接口
当然你也可以另起一个项目.

首先是配置服务的调用.为此工程添加一个配置文件:app.config
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <bindings>       
  5.       <wsHttpBinding>  
  6.         <binding name="testhttpswcfBinding" closeTimeout="00:01:00"  
  7.                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"  
  8.                    allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"  
  9.                    maxBufferPoolSize="268435456" maxReceivedMessageSize="268435456"  
  10.                    messageEncoding="Text" textEncoding="utf-8"  
  11.                    useDefaultWebProxy="true">  
  12.           <readerQuotas maxDepth="32" maxStringContentLength="2000000000" maxArrayLength="2000000000"  
  13.               maxBytesPerRead="2000000000" maxNameTableCharCount="65535" />  
  14.           <security mode="Transport">  
  15.             <transport clientCredentialType="None" proxyCredentialType="None"  
  16.                 realm="" />  
  17.             <message clientCredentialType="UserName" algorithmSuite="Default" />  
  18.           </security>  
  19.         </binding>          
  20.       </wsHttpBinding>  
  21.     </bindings>  
  22.     <client>  
  23.       <endpoint address="https://localhost/wcf/Service1.svc" binding="wsHttpBinding"  
  24.                       bindingConfiguration="testhttpswcfBinding"  
  25.                 contract="testhttpswcf.IService1"  
  26.                       name="testhttpsserverconfig" />  
  27.     </client>  
  28.   </system.serviceModel>  
  29. </configuration>  

这里没多少好说的.要注意的就是<security mode="Transport"> ,
 <endpoint中的bindingConfiguration="testhttpswcfBinding"  必须是上面配置的binding的name: <binding name="testhttpswcfBinding"
contract="testhttpswcf.IService1"必须是我们服务所实现的接口
endpoint name="testhttpsserverconfig"可以随便写..只要你需要保证它是唯 一即可
address="https://localhost/wcf/Service1.svc" 得指向你部署刚那个网站的地址

在工程中建一个class
代码如下:
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. using System.ServiceModel;  
  7. using System.ServiceModel.Channels;  
  8. using System.ServiceModel.Description;  
  9.   
  10. using System.Net;  
  11. using System.Net.Security;  
  12. using System.Security.Cryptography.X509Certificates;  
  13.   
  14. namespace testClient  
  15. {  
  16.     class ServerHelper  
  17.     {  
  18.         /// <summary>  
  19.         /// 与https建立信任关系  
  20.         /// </summary>  
  21.         public static void Init()  
  22.         {  
  23.             System.Net.ServicePointManager.ServerCertificateValidationCallback -= ValidateServerCertificate;  
  24.             System.Net.ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate;  
  25.         }  
  26.   
  27.         /// <summary>  
  28.         /// SSL回调  
  29.         /// </summary>  
  30.         /// <param name="sender"></param>  
  31.         /// <param name="certificate"></param>  
  32.         /// <param name="chain"></param>  
  33.         /// <param name="sslPolicyErrors"></param>  
  34.         /// <returns></returns>  
  35.         private static bool ValidateServerCertificate(object sender, X509Certificate certificate, 
  36. X509Chain chain, SslPolicyErrors sslPolicyErrors)  
  37.         {  
  38.             return true;  
  39.         }  
  40.   
  41.         /// <summary>  
  42.         /// 配置节点名称  
  43.         /// </summary>  
  44.         /// <typeparam name="T"></typeparam>  
  45.         /// <param name="endpointConfigurationName"></param>  
  46.         /// <returns></returns>  
  47.         public static T CreateRemoteObject<T>(string endpointConfigurationName)  
  48.         {  
  49.             var channelFactory = new ChannelFactory<T>(endpointConfigurationName);  
  50.             var proxy = channelFactory.CreateChannel();  
  51.             return proxy;  
  52.         }  
  53.     }  
  54. }  

其中方法init 为了避免出现无法建立信任的连接这个错误.
未处理 System.ServiceModel.Security.SecurityNegotiationException
  Message=无法为 SSL/TLS 安全通道与颁发机构“localhost”建立信任关系。

 
  InnerException: System.Net.WebException
       Message=基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。
       Source=System
       StackTrace:
            在 System.Net.HttpWebRequest.GetResponse()
            在 System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
       InnerException: System.Security.Authentication.AuthenticationException
            Message=根据验证过程,远程证书无效。

           

所以在调用远程方法前得调用此方法
现在可以在program中写下如下代码了:
  1. namespace testClient  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             Console.WriteLine("请输入一个数符串然后回车:");  
  8.             var str = Console.ReadLine();  
  9.   
  10.             ServerHelper.Init();  
  11.   
  12.             var serverclient = ServerHelper.CreateRemoteObject<testhttpswcf.IService1>("testhttpsserverconfig");  
  13.   
  14.             var result = serverclient.DoWork(str);  
  15.   
  16.             Console.WriteLine(result);  
  17.   
  18.             Console.ReadLine();  
  19.         }  
  20.     }  
  21. }  

运行程序如下:


可以看到结果是网站返回的

可能出现的错误:这可能是由于服务终结点绑定未使用 HTTP 协议造成的
这个可能有很多..我的是因为对象不一至造成的
比如类B继续类A,类C也继续类A..而服务中有个方法返回一个类A的集合....里面有B类也有C类..就造成了这种问题..也就是说必须是同一类型的类..基类相同也不行.不解.

下面是此实例的源码:本地下载

 

posted on 2011-11-22 17:18  生龙活虎1986  阅读(3861)  评论(1编辑  收藏  举报