1. Transfer Security
Transfer Security 主要包括三個方面: "消息完整性(Message Integrity)"、"消息機密性 (Message Confidentiality)" 和 "交互驗證(Mutual Authentication)"。
消息完整性必須確保消息在傳輸過程中沒有被篡改,接收的消息是完整且正確的;消息機密性必須確保消息不會被任何第三方查閱,消息內容不會洩漏給任何非相關人員;而交互認證則是指客戶端和服務器必須通過某種信任機制才能建立正確的連接,同時交互認證還要監測並阻止拒絕服務攻擊(DOS)。通常的做法是對消息進行數字簽名來確保其完整性,使用非對稱加密算法來阻止消息內容外洩,而用戶名/密碼、X.509 數字證書等方式則可以用來驗證對方身份,在這裡我們主要講述如何在WCF中使用用戶名/密碼的身份驗證方式.
2. 創建x.509數字證書:
要使用userName/password方式來驗證身份,我們需要為服務器裝一個證書,創建證書的作用是因為用戶名和密碼在client和service傳輸的過程中需要加密,否則就沒有安全性了,x.509rd使用非對稱加密加技術.用公鑰加密客戶端用戶名和密碼,在服務端用私鑰來解密,所以我們得創建這樣的證書.使用vs2008的tool中的command命令下執行:makecert -r -pe -n "CN=Temp" -ss My -sky exchange .我們就可以為服務器生成Temp的證書.如下圖所示.
點擊view可以查看詳細信息:
X.509 簡單證書介紹:
X.509給出的鑒別框架是一種基於公開密鑰體制的鑒別業務密鑰管理。一個用戶有兩把密鑰:一把是用戶的專用密鑰,另一把是其他用戶都可利用的公共密鑰。用戶可用常規密鑰(如DES)為信息加密,然後再用接收者的公共密鑰對DES進行加密並將之附於信息之上,這樣接收者可用對應的專用密鑰打開DES密鎖,並對信息解密。該鑒別框架允許用戶將其公開密鑰存放在它的目錄款項中。一個用戶如果想與另一個用戶交換秘密信息,就可以直接從對方的目錄款項中獲得相應的公開密鑰,用於各種安全服務。更多的可以參考MSDN3.Solution 結構如下圖:
solution:WCFValidationContract WCF contract.
WCFValidationClient WCF client端.
WCFValidationServices 主要是實現contract的類
WCFValidationHost..用於啟動WCF.
創建服務
[ServiceContract] public interface IUserName//對應solution中的WCFValidationContract.IUserName { [OperationContract] bool test(); } public class UserName:IUserName//對應solution中的WCFValidationServices.UserName { #region IUserName Members public bool test() { return true; } #endregion }
我們通過繼承 UserNamePasswordValidator 來創建一個自定義驗證器。
//對應solution中的WCFValidationServices.MyValidation public override void Validate(string userName, string password) { //the follow code is testing only.u can read userName and password from DataBase. if (userName != "user" || password != "pwd") { throw new Exception("Unknown Username or Password"); } }
服務端的配置文件如下:
(host的配置文件) <?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="UserNameBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> <serviceCredentials> <issuedTokenAuthentication allowUntrustedRsaIssuers="true"></issuedTokenAuthentication> <clientCertificate> <authentication certificateValidationMode="None"/> </clientCertificate> <serviceCertificate findValue="Temp" storeLocation="CurrentUser" x509FindType="FindBySubjectName"/> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFValidationServices.MyValidation,WCFValidationServices"/> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors> <bindings> <wsHttpBinding> <binding name="userBinding"> <security mode="Message"> <message clientCredentialType="UserName"/> </security> </binding> </wsHttpBinding> </bindings> <services> <service behaviorConfiguration="UserNameBehavior" name="WCFValidationServices.UserName"> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="userBinding" name ="username" contract="WCFValidation.IUserName"> </endpoint> <host> <baseAddresses> <add baseAddress="http://localhost/userName"/> </baseAddresses> </host> </service> </services> </system.serviceModel> </configuration>
有時候我們在啟動服務的時候會生產如下的錯誤:
這時我們需要使用微軟件提供的WCF Samples中的一個工具FindPrivateKey來長到Temp的私鑰文件的位置,然後為ASPNET或NET Service用戶分配訪問權限
WCF Samples下載地址 http://download.csdn.net/source/792492也可以到MSDN上下載FindPrivateKey的使用介始:
http://msdn.microsoft.com/zh-cn/vbasic/aa717039.aspx4
.
創建客戶端
啟動服務器後,創建客戶端代理文件。注意自動生成的客戶端配置文件中包含了服務器數字證書的相關信息。<?xml version="1.0" encoding="utf-8"?>
<configuration> <system.serviceModel> <bindings> <wsHttpBinding> <binding name="username" 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="Windows" proxyCredentialType="None" realm="" /> <message clientCredentialType="UserName" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" /> </security> </binding> </wsHttpBinding> </bindings> <client> <endpoint address="http://localhost/userName" binding="wsHttpBinding" bindingConfiguration="username" contract="IUserName" name="username"> <identity> <certificate encodedValue="AwAAAAEAAAAUAAAAqxw7daba6mcItJ/tKIAFZfz3TCggAAAAAQAAAPcBAAAwggHzMIIBXKADAgECAhAciN6VY5e8ik4b7Ia5KvftMA0GCSqGSIb3DQEBBAUAMBMxETAPBgNVBAMTCE15U2VydmVyMB4XDTA4MTEyMDA2MTQwNloXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMITXlTZXJ2ZXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALK4gy7ldnVwSjemT3bQjKSEGd/zBjNqYDHf9kwUopwvuHpE287yWD1ytKaYYZf7uEdEtNYKwWeOwSNLEPqxUSW4jF92IqfQwkxa0bQdZQK/Y3TpmseX/hsOtW0FBXV3Ftqq+acrWVkG/J/HFM1eeIyPggVI/QqclrKjBQeikjMdAgMBAAGjSDBGMEQGA1UdAQQ9MDuAEEvEZkpRY3c664NiQiazM3+hFTATMREwDwYDVQQDEwhNeVNlcnZlcoIQHIjelWOXvIpOG+yGuSr37TANBgkqhkiG9w0BAQQFAAOBgQAQLrEU3mnxOlDkKuVx9OatXd0w99I3xMnQOsWvOCITjQrfUeJWz1FOl46pKAXDhJNgfMW133E3ARgUxf+abkJqz9ejhjvzJwx2CJYe843h98fooTPPbSs6rQrfQOxb/KoaxbKoxUaALQsGssEXkN2ImS0jsOUm9aVNnRNWpKMhzA==" /> </identity> </endpoint> </client> </system.serviceModel> </configuration>
以配置文件是由svcutil工具生成的.我們在客戶端寫以下代碼來調用服務:
UserNameClient aa = new UserNameClient(); aa.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None; aa.ClientCredentials.UserName.UserName = "user"; aa.ClientCredentials.UserName.Password = "pwd"; bool flag = aa.test(); Console.WriteLine(flag.ToString()); Console.ReadKey();
這時我們可以在控制應用程序中顯示True這個值.當我們輸入一個錯誤的密碼時如:
aa.ClientCredentials.UserName.UserName = "123"; aa.ClientCredentials.UserName.Password = "123";
客戶端就會有異常:
這樣我們不可以完成了WCF的 userName/password的驗證方式,在項目中使用時,我們不必要在每次調用方法的時候設置用戶名和密碼,我們只要寫一個基類就可以了