• 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类..就造成了这种问题..也就是说必须是同一类型的类..基类相同也不行.不解.

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

     

  • 相关阅读:
    xtrabackup
    spark对机器的要求
    hbase的总结
    TO B公司高效能的组织建设实践
    如何给客户展示实力
    什么样的IT队伍是好队伍
    程序员如何使用OKR
    云原生
    Flink 的18个小知识点
    apt 常用命令
  • 原文地址:https://www.cnblogs.com/stragon/p/2259092.html
Copyright © 2020-2023  润新知