WCF的https安全(ssl)访问实例
近来用WCF应用的时候,需要部署到IIS以https的安全连接访问
虽然网上此类教程不少.但我还是郁闷了很久..主要是小问题..在此写下.以免大家犯同样的错误
下面看 我一步一步做..(注:以下所有工程都得引用:System.ServiceModel)
首先用VS建个网站和一个接口工程:testhttpswcf , testhttpswcf.IServer
在工程testhttpswcf.IServer中添加一个接口:IService1.cs
代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.ServiceModel;
- using System.Text;
- namespace testhttpswcf
- {
- // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。
- [ServiceContract]
- public interface IService1
- {
- [OperationContract]
- string DoWork(string s);
- }
- }
网站:testhttpswcf 引用此接口工程,并建一个WCF服务.让其实现上面的接口
如下代码:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Runtime.Serialization;
- using System.ServiceModel;
- using System.Text;
- using System.ServiceModel.Activation;
- namespace testhttpswcf
- {
- // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
- [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
- public class Service1 : IService1
- {
- public string DoWork(string s)
- {
- return "您输入了:"+s;
- }
- }
- }
下面是配置WCF服务,打开服务网站的web.config
添加节点如下:
- <?xml version="1.0" encoding="utf-8"?>
- <!--
- 有关如何配置 ASP.NET 应用程序的详细消息,请访问
- http://go.microsoft.com/fwlink/?LinkId=169433
- -->
- <configuration>
- <system.web>
- <compilation debug="true" targetFramework="4.0" />
- </system.web>
- <system.serviceModel>
- <bindings>
- <wsHttpBinding>
- <binding name="AllBindingConfiguration">
- <security mode="Transport">
- <transport clientCredentialType="None" />
- </security>
- </binding>
- </wsHttpBinding>
- </bindings>
- <client />
- <behaviors>
- <serviceBehaviors>
- <behavior name="AllbehaviorConfiguration">
- <serviceMetadata httpsGetEnabled="true" />
- <serviceDebug includeExceptionDetailInFaults="false" />
- </behavior>
- </serviceBehaviors>
- </behaviors>
- <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
- <services>
- <service name="testhttpswcf.Service1" behaviorConfiguration="AllbehaviorConfiguration">
- <endpoint address="" binding="wsHttpBinding" contract="testhttpswcf.IService1"
- bindingConfiguration="AllBindingConfiguration" >
- </endpoint>
- <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
- </service>
- </services>
- </system.serviceModel>
- </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>
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
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <bindings>
- <wsHttpBinding>
- <binding name="testhttpswcfBinding" closeTimeout="00:01:00"
- openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
- allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
- maxBufferPoolSize="268435456" maxReceivedMessageSize="268435456"
- messageEncoding="Text" textEncoding="utf-8"
- useDefaultWebProxy="true">
- <readerQuotas maxDepth="32" maxStringContentLength="2000000000" maxArrayLength="2000000000"
- maxBytesPerRead="2000000000" maxNameTableCharCount="65535" />
- <security mode="Transport">
- <transport clientCredentialType="None" proxyCredentialType="None"
- realm="" />
- <message clientCredentialType="UserName" algorithmSuite="Default" />
- </security>
- </binding>
- </wsHttpBinding>
- </bindings>
- <client>
- <endpoint address="https://localhost/wcf/Service1.svc" binding="wsHttpBinding"
- bindingConfiguration="testhttpswcfBinding"
- contract="testhttpswcf.IService1"
- name="testhttpsserverconfig" />
- </client>
- </system.serviceModel>
- </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
代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
- using System.ServiceModel.Description;
- using System.Net;
- using System.Net.Security;
- using System.Security.Cryptography.X509Certificates;
- namespace testClient
- {
- class ServerHelper
- {
- /// <summary>
- /// 与https建立信任关系
- /// </summary>
- public static void Init()
- {
- System.Net.ServicePointManager.ServerCertificateValidationCallback -= ValidateServerCertificate;
- System.Net.ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate;
- }
- /// <summary>
- /// SSL回调
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="certificate"></param>
- /// <param name="chain"></param>
- /// <param name="sslPolicyErrors"></param>
- /// <returns></returns>
- private static bool ValidateServerCertificate(object sender, X509Certificate certificate,
- X509Chain chain, SslPolicyErrors sslPolicyErrors)
- {
- return true;
- }
- /// <summary>
- /// 配置节点名称
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="endpointConfigurationName"></param>
- /// <returns></returns>
- public static T CreateRemoteObject<T>(string endpointConfigurationName)
- {
- var channelFactory = new ChannelFactory<T>(endpointConfigurationName);
- var proxy = channelFactory.CreateChannel();
- return proxy;
- }
- }
- }
其中方法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中写下如下代码了:
- namespace testClient
- {
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("请输入一个数符串然后回车:");
- var str = Console.ReadLine();
- ServerHelper.Init();
- var serverclient = ServerHelper.CreateRemoteObject<testhttpswcf.IService1>("testhttpsserverconfig");
- var result = serverclient.DoWork(str);
- Console.WriteLine(result);
- Console.ReadLine();
- }
- }
- }
运行程序如下:
可以看到结果是网站返回的
可能出现的错误:这可能是由于服务终结点绑定未使用 HTTP 协议造成的
这个可能有很多..我的是因为对象不一至造成的
比如类B继续类A,类C也继续类A..而服务中有个方法返回一个类A的集合....里面有B类也有C类..就造成了这种问题..也就是说必须是同一类型的类..基类相同也不行.不解.
下面是此实例的源码:本地下载