【转】x.509证书在WCF中的应用(CS篇)
【轉(zhuǎn)自】x.509證書在WCF中的應(yīng)用(CS篇)
?
?
為什么要用x.509證書?
WCF的服務(wù)端和客戶端之間,如 果不作任何安全處理(即服務(wù)端的<security mode="None">),則所有傳輸?shù)南⒁悦魑姆绞綕M天飛,在internet/intranet環(huán)境下無疑是很不安全的,這就是用證書的 目的。(當(dāng)然WCF還有其它安全機(jī)制,比如最常見的UserName方式,但通常每次都要從數(shù)據(jù)庫讀取用戶名/密碼信息進(jìn)行驗證,比較麻煩,開銷也大,個 人覺得還是證書最為方便)--關(guān)于x.509證書
的基本知識,可參見http://www.cnblogs.com/yjmyzz/archive/2008/08/19/1271171.html
大致原理(個人理解,可能不太準(zhǔn)確):
正確設(shè)置服務(wù)端與客戶端證書后,WCF的服務(wù)端啟動時,需要利用服務(wù)端證書驗證,如果驗證通過將正常啟動,否則報異常,同時客戶端調(diào)用服務(wù)端方法時,也需要提供客戶端證書,服務(wù)端接受到客戶端證書后,驗證客戶端證書的有效性,如果通過,則允許客戶端正常調(diào)用。
?
下面將逐步講解如何使用:
1.制作證書
先進(jìn)入到vs2008的命令行狀態(tài),即:
開始-->程序-->Microsoft Visual Studio 2008-->Visual Studio Tools-->Visual Studio 2008 命令提示
鍵入:
makecert?-r?-pe?-n?"CN=MyServer"?-ss?My?-sky?exchange解釋一下:makecert.exe是一個專門用來制作證書的小工具,上面一行的意思就是制作一個CN=MyServer的服務(wù)器證書,默認(rèn)存儲在CurrentUser"My這個位置,同時這個證書標(biāo)識為可導(dǎo)出。(詳細(xì)的
MakeCert參數(shù)可參見http://msdn.microsoft.com/zh-cn/bfsktky3(vs.80).aspx)
再輸入:
makecert?-r?-pe?-n?"CN=MyClient"?-ss?My?-sky?exchange生成客戶端證書,證書生成好以后,可以在IE里查看到,IE-->工具-->Internet選項-->內(nèi)容-->證書
同時如何管理已經(jīng)安裝的證書,可參見http://www.cnblogs.com/yjmyzz/archive/2008/08/20/1272128.html
2.wcf服務(wù)端
vs.net2008啟動后,新建一個控制臺應(yīng)用程序-->(右擊)添加-->新建項-->WCF服務(wù)-->命名為MyService.cs-->保存
保存后,系統(tǒng)會自動生成一個接口文件IMyService.cs
二個文件的內(nèi)容如下:
IMyService.cs
using?System.ServiceModel;
namespace?Server
{
????//?注意:?如果更改此處的接口名稱?"IMyService",也必須更新?App.config?中對?"IMyService"?的引用。
????[ServiceContract]
????public?interface?IMyService
????{
????????[OperationContract]
????????string?Test();
????}
}
MyService.cs
using?System.ServiceModel;
namespace?Server
{
????//?注意:?如果更改此處的類名?"MyService",也必須更新?App.config?中對?"MyService"?的引用。
????public?class?MyService?:?IMyService
????{
????????public?string?Test()
????????{
????????????Console.WriteLine("服務(wù)端輸出:"n"?+?ServiceSecurityContext.Current.PrimaryIdentity.AuthenticationType);
????????????Console.WriteLine(ServiceSecurityContext.Current.PrimaryIdentity.Name);
????????????return?"服務(wù)端時間:"?+?DateTime.Now.ToString();?
????????}
????}
}
再來新建一個cs文件:CustomX509CertificateValidator.cs
內(nèi)容先貼在下面
using?System.Security.Cryptography.X509Certificates;
using?System.IdentityModel.Tokens;
using?System.IdentityModel.Selectors;
namespace?Server
{
????public?class?CustomX509CertificateValidator?:?X509CertificateValidator
????{
????????public?override?void?Validate(X509Certificate2?certificate)
????????{
????????????Console.WriteLine(certificate.Subject);
????????????Console.WriteLine(certificate.Thumbprint);?
????????????if?(certificate.Thumbprint?!=?"3E4D4B64A90810B6CFF9B1DD2390D8C9488747BF")
????????????????throw?new?SecurityTokenException("Certificate?Validation?Error!");
????????}
????}
}
?
注意:項目必須先添加對System.IdentityModel的引用
解釋一下:
這個文件的用戶是:客戶端要調(diào)用服務(wù)端方法,并提供客戶端證書時,用來驗證客戶端證書的有效性。注意里面的if (certificate.Thumbprint != "3E4D4B64A90810B6CFF9B1DD2390D8C9488747BF")這一句,大家調(diào)試的時候,里面的 3E4D4B64A90810B6CFF9B1DD2390D8C9488747BF要換成你自己的客戶端證書的信息(每一個證書對應(yīng)的這一串字符都是唯 一的),可通過在IE瀏覽器里,查看MyClient證書的詳細(xì)信息得到,見下圖:
同時注意配置文件App.Config,內(nèi)容如下
<configuration>
????<system.serviceModel>
????????<behaviors>
????????????<serviceBehaviors>
????????????????<behavior?name="Server.MyServiceBehavior">
??????????????????<serviceMetadata?httpGetEnabled="true"?httpGetUrl="http://localhost:8080"?/>
??????????????????<serviceDebug?includeExceptionDetailInFaults="true"?/>
??????????????????<serviceCredentials>
????????????????????<clientCertificate>
??????????????????????<authentication?certificateValidationMode="Custom"?customCertificateValidatorType="Server.CustomX509CertificateValidator,Server"/>
????????????????????</clientCertificate>
????????????????????<serviceCertificate?findValue="MyServer"?storeLocation="CurrentUser"
??????????????????????x509FindType="FindBySubjectName"?/>
??????????????????</serviceCredentials>
????????????????</behavior>
????????????</serviceBehaviors>
????????</behaviors>
??????<bindings>
????????<netTcpBinding>
??????????<binding?name="NewBinding0">
????????????<security?mode="Transport">
??????????????<transport?clientCredentialType="Certificate"?/>
????????????</security>
??????????</binding>
????????</netTcpBinding>
??????</bindings>
????????<services>
????????????<service?behaviorConfiguration="Server.MyServiceBehavior"?name="Server.MyService">
????????????????<endpoint?address="net.tcp://localhost:8081"?binding="netTcpBinding"?contract="Server.IMyService"?bindingConfiguration="NewBinding0"/>??????????????
????????????</service>
????????</services>
????</system.serviceModel>
</configuration>
?
解釋一下:
<authentication certificateValidationMode="Custom" customCertificateValidatorType="Server.CustomX509CertificateValidator,Server"/></clientCertificate>
這一行的意思就是通知WCF服務(wù)端,驗證客戶端證書的模式為自定義,驗證時調(diào)用Server.CustomX509CertificateValidator這個類來完成驗證
<serviceCertificate findValue="MyServer" storeLocation="CurrentUser" x509FindType="FindBySubjectName" />
這一行的意思是WCF服務(wù)端驗證證書時,到CurrentUser這個位置查詢CN=MyServer的證書
最后在Program.cs里啟用WCF,內(nèi)容如下:
using?System;??using?System.ServiceModel;
namespace?Server
{
????class?Program
????{
????????static?void?Main(string[]?args)
????????{
????????????ServiceHost?host?=?new?ServiceHost(typeof(MyService));
????????????host.Open();
????????????Console.ReadKey();
????????}
????}
}
?
build一下,如果編譯無錯的話,服務(wù)端完工,可以運行一下,將彈出一個DOS命令窗口(不過什么輸出也沒有),只要不報錯,就表明Ok了,先不要急著關(guān),嘗試瀏覽一下:
http://localhost:8080/(這個地址哪里來的?回頭看下App.config,里面有一行<serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8080/" />,呵呵,明白了吧) 正常的話,應(yīng)該類似下圖所示:
3.客戶端調(diào)用
下面生成服務(wù)端的代理和配置文件,客戶端開發(fā)將用到這二個文件,同樣先進(jìn)入vs2008的命令行狀態(tài),輸入:
svcutil.exe http://localhost:8080/ /d:c:"123"
注意:輸入這一行命令的時候,請確保服務(wù)端程序正在運行。這一句的意思就是在c:"123"目錄下輸出WCF的代理文件和配置文件
打開vs.net2008,再新建一個控制臺應(yīng)用程序,可以命名為Client
把c:"123"下生成的二個文件MyService.cs,output.config添加到Client項目中,同時將output.config改名為App.Config
Progam.cs代碼內(nèi)容如下:
using?System;?namespace?Client
{
????class?Program
????{
????????static?void?Main(string[]?args)
????????{
????????????using?(MyServiceClient?client?=?new?MyServiceClient())
????????????{
????????????????Console.WriteLine("客戶端輸出:");
????????????????Console.WriteLine(client.Test());
????????????}?
????????????Console.ReadKey();
????????}
????}
}
同時,參考下面的內(nèi)容手動修改一下App.Config文件
<?xml?version="1.0"?encoding="utf-8"?><configuration>
????<system.serviceModel>
??????<behaviors>
????????<endpointBehaviors>
??????????<behavior?name="NewBehavior">
????????????<clientCredentials>
??????????????<clientCertificate?findValue="MyClient"?x509FindType="FindBySubjectName"/>
??????????????<serviceCertificate>
????????????????<authentication?certificateValidationMode="None"?/>
??????????????</serviceCertificate>
????????????</clientCredentials>
??????????</behavior>
????????</endpointBehaviors>
??????</behaviors>
??????<bindings>
????????????<netTcpBinding>
????????????????<binding?name="NetTcpBinding_IMyService"?closeTimeout="00:01:00"
????????????????????openTimeout="00:01:00"?receiveTimeout="00:10:00"?sendTimeout="00:01:00"
????????????????????transactionFlow="false"?transferMode="Buffered"?transactionProtocol="OleTransactions"
????????????????????hostNameComparisonMode="StrongWildcard"?listenBacklog="10"
????????????????????maxBufferPoolSize="524288"?maxBufferSize="65536"?maxConnections="10"
????????????????????maxReceivedMessageSize="65536">
????????????????????<readerQuotas?maxDepth="32"?maxStringContentLength="8192"?maxArrayLength="16384"
????????????????????????maxBytesPerRead="4096"?maxNameTableCharCount="16384"?/>
????????????????????<reliableSession?ordered="true"?inactivityTimeout="00:10:00"
????????????????????????enabled="false"?/>
????????????????????<security?mode="Transport">
????????????????????????<transport?clientCredentialType="Certificate"?protectionLevel="EncryptAndSign"?/>
????????????????????????<message?clientCredentialType="Windows"?/>
????????????????????</security>
????????????????</binding>
????????????</netTcpBinding>
????????</bindings>
????????<client>
????????????<endpoint?address="net.tcp://localhost:8081/"?binding="netTcpBinding"
????????????????bindingConfiguration="NetTcpBinding_IMyService"?contract="IMyService"
????????????????name="NetTcpBinding_IMyService"?behaviorConfiguration="NewBehavior">
????????????????<identity>
????????????????????<dns?value="MyServer"?/>
????????????????</identity>
????????????</endpoint>
????????</client>
????</system.serviceModel>
</configuration>
?
主要是增加了一個節(jié)點
<behaviors>
??????? <endpointBehaviors>
????????? <behavior name="NewBehavior">
??????????? <clientCredentials>
????????????? <clientCertificate findValue="MyClient" x509FindType="FindBySubjectName"/>
????????????? <serviceCertificate>
??????????????? <authentication certificateValidationMode="None" />
????????????? </serviceCertificate>
??????????? </clientCredentials>
????????? </behavior>
??????? </endpointBehaviors>
????? </behaviors>
上面紅色的行,就是表明客戶端調(diào)用時,將用MyClient證書來驗證
?
同時<endpoint address="net.tcp://localhost:8081/" binding="netTcpBinding"
??????????????? bindingConfiguration="NetTcpBinding_IMyService" contract="IMyService"
??????????????? name="NetTcpBinding_IMyService" behaviorConfiguration="NewBehavior">這一句,增加了behaviorConfiguration="NewBehavior"
好了,Build一下,沒有問題的話,開發(fā)完成
4.測試:
先啟動服務(wù)端,再啟動客戶端,運行結(jié)果如下:
(轉(zhuǎn)貼請注明來自"菩提樹下的楊過") http://www.cnblogs.com/yjmyzz/archive/2008/08/20/1272550.html
?
注意服務(wù)端server.exe輸出的信息中3E4D4B64A90810B6CFF9B1DD2390D8C9488747BF與客戶端證書完全吻合
最后來談?wù)劮职l(fā)問題,上面這一系列測試都是在同一臺機(jī)器完成的,客戶端總不可能總是跟服務(wù)端在一臺機(jī)器上,這個好辦,在IE里把MyClient證書導(dǎo)出,注意導(dǎo)出時要選擇"是,導(dǎo)出私鑰",然后把導(dǎo)出的pfx文件連同客戶端程序一起分發(fā)到目標(biāo)客戶機(jī)即可,這里要注意幾點:
a.客戶端上的App.config里,要把<endpoint address="net.tcp://localhost:8081/" 中的localhost換成服務(wù)端的Ip地址
b.注意防火墻參數(shù)設(shè)置(本例中,即要把tcp:8081端口打開)
?
總結(jié)
以上是生活随笔為你收集整理的【转】x.509证书在WCF中的应用(CS篇)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用ADO.NET的参数集合来有效防止S
- 下一篇: 测试Live Write的插件