WCF wsHttpBinding协议和x509证书创建和部署篇
希望对大家有所帮助
开发环境:Win7系统+VS2010
WCF考虑传输安全性,X509证书验证。
WCF创建X509证书步骤:
1.把C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\makecert.exe文件复制一份到其他盘符,我这里就放在我自己的F盘cer文件夹下.
2.以管理员身份:运行:C:\Windows\System32\cmd.exe
3.如何创建证书:
makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=TestServer -sky exchange -pe (服务端证书)
makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=TestClient -sky exchange -pe (客户端证书)
各种参数的介绍
属性解析
-sr
指定的证书存储区中的注册表位置。
currentUser
指定注册版存储位置为 HKEY_CURRENT_USER.
localMachine
指定注册版存储位置为 HKEY_LOCAL_MACHINE.
-ss
指定证书存储的位置。
-a
指定相关的算法,可以选择 MD5 算法或者 SHA1算法
-n
指定证书的名称。该名称遵循X.500命名标准。简单例子如 "CN=MyName" 格式,如果没有指定/n开关,证书默认的名称是"Joe's Software Emporium"。
-sky
证书键类型。可以设置为 exchange 或者 signature。
-pe
证书可导出
创建证书成功—
4.在开始-运行(输入mmc)如下图
5.点击文件-选择添加/删除管理单元
证书就创建OK了。
6.导出证书:选中证书—右击—导出—下一步—如下图
WCF ——wsHttpBinding协议+x509证书
VS2010创建服务端:
1.打开vs2010—文件—新建—项目-创建一个Windows窗体应用程序命名为:WCFServerwsHttpBinding—选中WCFServerwsHttpBinding右击—属性—应用程序—目标框架.NET Framework 4 Client Profile改成 .NET Framework 4
2.右击解决方案'WCFServerwsHttpBinding'—添加—新建项目—WCF—WCF服务库命名为:WcfService—选中WcfService右击—属性—应用程序—目标框架.NET Framework 4 Client Profile改成 NET Framework 4
3.在窗体"Form1"布局如下图:
4.窗体加载事件:
private void Form1_Load(object sender, EventArgs e) { this.textBox1.Text = "192.168.15.195"; this.textBox2.Text = "8085"; }
5.点击开启服务按钮事件:
ServiceHost (class类)要引用:using System.ServiceModel;名称空间
和引用WcfService服务库。
//宿主服务 ServiceHost Host; private void button1_Click(object sender, EventArgs e) { Uri uri = null; if (Uri.TryCreate("http://" + textBox1.Text + ":" + textBox2.Text + "", UriKind.Absolute, out uri)) { Host = new ServiceHost(typeof(WcfService.Service1), uri); //服务启动禁用按钮 Host.Opened += new EventHandler((s1, e1) => { this.button1.Enabled = false; } ); //服务关闭开启按钮 Host.Closed += new EventHandler((s2, e2) => { this.button1.Enabled = true; } ); //打开服务 Host.Open(); } }
6.窗体关闭事件:
private void Form1_Load(object sender, EventArgs e) { //关闭服务 if (Host != null) Host.Close(); }
7.在服务库WcfService项目中接口IService1.cs类中定义一个方法:
[OperationContract]//操作契约 string GetSum(int i, int j);
在服务库WcfService项目中Service1.cs类中实现接口IService1.cs类中定义的GetSum方法
8.服务端App.config配置:重点哦!
<?xml version="1.0"?> <configuration> <appSettings> <!--客服端x509证书名称配置信息--> <add key="ClientCertName" value="HHJiTuanClient"/> </appSettings> <system.web> <compilation debug="true"/> </system.web> <!-- 部署服务库项目时,必须将配置文件的内容添加到 主机的app.config 文件中。system.Configuration 不支持库的配置文件--> <system.serviceModel> <services> <service name="WcfService.Service1" behaviorConfiguration="Custombehavior"> <!--<host> <baseAddresses> <add baseAddress = "http://localhost:8732/Design_Time_Addresses/WcfService/Service1/" /> </baseAddresses> </host>--> <!-- Service Endpoints --> <!-- 除非完全限定,否则地址将与上面提供的基址相关--> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="Custombinding" contract="WcfService.IService1" behaviorConfiguration="wsHttpbehavior"> <!-- 部署时,应删除或替换下列标识元素,以反映 用来运行所部署服务的标识。删除之后,WCF将 自动推断相应标识--> <!--<identity> <dns value="localhost"/> </identity>--> </endpoint> <!-- Metadata Endpoints --> <!-- 元数据交换终结点供相应的服务用于向客户端做自我介绍。 --> <!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除--> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="Custombehavior"> <!-- 为避免泄漏元数据信息, 请在部署前将以下值设置为false 并删除上面的元数据终结点? --> <serviceMetadata httpGetEnabled="false"/> <!-- 要接收故障异常详细信息以进行调试, 请将以下值设置为true。在部署前设置为false 以避免泄漏异常信息--> <serviceDebug includeExceptionDetailInFaults="True"/> <serviceCredentials> <!-- 服务端采用证书详细配置 findValue :创建服务证书名称 storeName:证书储存详细位于哪? storeLocation :证书储存位于当前本机用户 X509FindType : x509查找证书主题名?--> <serviceCertificate findValue="HHJiTuanServer" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/> <!--客户端验证方式--> <clientCertificate> <!--authentication(证明;鉴定;证实),--> <authentication certificateValidationMode="Custom" customCertificateValidatorType="WcfService.CustomX509CertificateValidator,WcfService"/> </clientCertificate> </serviceCredentials> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="wsHttpbehavior"> </behavior> </endpointBehaviors> </behaviors> <bindings> <wsHttpBinding> <binding name="Custombinding" maxReceivedMessageSize="2147483647" receiveTimeout="01:00:00" sendTimeout="01:00:00"> <security mode="Message"> <transport clientCredentialType="None"></transport> <message clientCredentialType="Certificate" establishSecurityContext="true" negotiateServiceCredential="true"/> </security> </binding> </wsHttpBinding> </bindings> </system.serviceModel> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration>
9.服务端x509证书验证代码:
在项目WcfService中添加一个CustomX509CertificateValidator.cs类文件用来重写(override) X509CertificateValidator类中的Validate()方法;注意:要添加引用:
using System.IdentityModel 命名空间
CustomX509CertificateValidator.cs中的代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography.X509Certificates; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.IO; namespace WcfService { public class CustomX509CertificateValidator:X509CertificateValidator { public override void Validate(X509Certificate2 certificate) { if (certificate == null) throw new ArgumentNullException("X509认证证书为空!"); X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite); X509Certificate2Collection fcollection = (X509Certificate2Collection)store.Certificates; string ClientCertName = System.Configuration.ConfigurationManager.AppSettings["ClientCertName"].ToString(); X509Certificate2Collection collection=fcollection.Find(X509FindType.FindBySubjectName,ClientCertName,false); if (collection.Count > 0) { X509Certificate2 clientCertificate = new X509Certificate2(collection[0]); if (!certificate.Thumbprint.Equals(clientCertificate.Thumbprint, StringComparison.CurrentCultureIgnoreCase)) throw new SecurityTokenException("客户端证书没有验证通过!"); } else { throw new SecurityTokenException("X509认证证书为空!"); } } } }
服务端:WCF+X509证书就OK了;注意:以管理员身份开启服务的。
VS2010创建客户端:
1.打开vs2010—文件—新建—项目-创建一个Windows窗体应用程序命名为:WCFClientwsHttpBinding
2.右击引用—添加服务引用—如下图
3.客户端app.config配置信息如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <wsHttpBinding> <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Message"> <transport clientCredentialType="None" proxyCredentialType="None" realm="" /> <message clientCredentialType="Certificate" negotiateServiceCredential="true" algorithmSuite="Default" /> </security> </binding> </wsHttpBinding> </bindings> <behaviors> <endpointBehaviors> <behavior name="CustomBehavior"> <clientCredentials> <!--客户端证书--> <!-- 客户端采用证书详细配置 findValue :创建证书名称 storeName:证书储存详细位于哪 storeLocation :证书储存位于当前本机用户 X509FindType : x509查找证书主题名--> <clientCertificate findValue="HHJiTuanClient" storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName"/> <serviceCertificate> <authentication certificateValidationMode="None"/> </serviceCertificate> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <client> <endpoint address="http://192.168.15.195:8085/" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" contract="ServiceClient.IService1" name="WSHttpBinding_IService1" behaviorConfiguration="CustomBehavior"> <identity> <!--服务引用成功后,会自动生成encodedValue值--> <certificate encodedValue="AwAAAAEAAAAUAAAAM23h/apE+wFi9Hmt2xqvdNlOvCkgAAAAAQAAALoBAAAwggG2MIIBZKADAgECAhCY/72TOnaznkTCvSHo7nwOMAkGBSsOAwIdBQAwFjEUMBIGA1UEAxMLUm9vdCBBZ2VuY3kwHhcNMTIwNjA2MDEwNjIyWhcNMzkxMjMxMjM1OTU5WjAZMRcwFQYDVQQDEw5ISEppVHVhblNlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAup8v0UnzE3Q8xPCd1C6Vg2Lan/EYgsseULmIxUC+577SpuIwpToHl7l7VfBDR0rRpBCDogFeUsTnMVEOuohee4FtAn1BS1ujxWHRNd01igAw17LcNlomKvjrBBD0BbHLcDAmvVcNdgl4Mf8VpYocLTr3A1IF8eDogpvMA5jreAMCAwEAAaNLMEkwRwYDVR0BBEAwPoAQEuQJLQYdHU8AjWEh3BZkY6EYMBYxFDASBgNVBAMTC1Jvb3QgQWdlbmN5ghAGN2wAqgBkihHPuNSqXDX0MAkGBSsOAwIdBQADQQARnQUypjAUvRseCRVLi0dBBgxjJf2To8UDcezyYJLEsmNzWog0hNQGgn1fwqUhOIzCmg76TavBsbYg3RiLXyAQ" /> </identity> </endpoint> </client> </system.serviceModel> </configuration>
4.在窗体Form1中拖一个按钮,按钮Text文本"X509证书测试",触发点击按钮事件:
ServiceClient.Service1Client Client = new ServiceClient.Service1Client(); private void button1_Click(object sender, EventArgs e) { //如果客户端app.config文件没有配置证书验证节点就用用下一个代码来做客户端证书验证方法 //client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "HHJiTuanClient"); //下面注释是用户名和密码验证 //Client.ClientCredentials.UserName.UserName = "yangfeizai"; //Client.ClientCredentials.UserName.Password = "123456"; MessageBox.Show(Client.GetSum(10, 10)); }
这样WCF+X509就全部完成了!OK
certificateValidationMode有如下几种属性:
None= 未执行任何证书验证
PeerTrust=如果证书位于被信任的人的存储区中,则有效
ChainTrust=如果该链在受信任的根存储区生成证书颁发机构,则证书有效
PeerOrChainTrust=如果证书位于被信任的人的存储区或该链在受信任的根存储区生成证书颁发机构,则证书有效
Custom=用户必须插入自定义 X509CertificateValidator以验证证书(这种模式很有意思,后面会提到)
如果整体测试有错:
1.WCF服务是不是以管理员身份运行的
2.看是不是证书权限问题:如果是就给证书添加Everyone账号和相应的权限