上一篇文章中介紹瞭如何使用wsHttpBinding構建UserName受權的WCF應用程序,本文將爲您介紹如何使用wsHttpBinding構建基於SSL的UserName安全受權的WCF應用程序。html
與上篇文章同樣,一樣將該示例分爲服務端與客戶端介紹。windows
1. 服務端安全
(1) 實現CustomUserNameValidatorapp
首先實現CustomUserNameValidator,如何建立CustomUserNameValidator請參見第一篇與第二篇文章。ide
1 public class CustomUserNameValidator : UserNamePasswordValidator 2 { 3 private const string USERNAME_ELEMENT_NAME = "userName"; 4 5 private const string PASSWORD_ELEMENT_NAME = "password"; 6 7 private const string FAULT_EXCEPTION_MESSAGE = "UserName or Password is incorrect!"; 8 9 public override void Validate(string userName, string password) 10 { 11 Guarder.Guard.ArgumentNotNull(userName) 12 .ArgumentNotNull(password); 13 var validateUserName = ConfigurationManager.AppSettings[USERNAME_ELEMENT_NAME]; 14 var validatePassword = ConfigurationManager.AppSettings[PASSWORD_ELEMENT_NAME]; 15 var validateCondition = userName.Equals(validateUserName) && password.Equals(validatePassword); 16 if (!validateCondition) 17 { 18 throw new FaultException(FAULT_EXCEPTION_MESSAGE); 19 } 20 } 21 }
(2) 註冊服務端證書ui
與上篇文章中同樣,首先須要向currentUser或localMachine中註冊一個X509證書。this
1 makecert.exe -sr CurrentUser -ss My -a sha1 -n CN=ServerCert -sky exchange –pe
(3) 完成服務端配置文件加密
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <startup> 4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 5 </startup> 6 <appSettings> 7 <add key="username" value="username"/> 8 <add key="password" value="password"/> 9 </appSettings> 10 <system.serviceModel> 11 <behaviors> 12 <serviceBehaviors> 13 <behavior name="securityBehavior"> 14 <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /> 15 <serviceDebug includeExceptionDetailInFaults="true" /> 16 <serviceCredentials> 18 <serviceCertificate 19 findValue="ServerCert" 20 x509FindType="FindBySubjectName" 21 storeLocation="CurrentUser" 22 storeName="My"/> 23 <userNameAuthentication 24 userNamePasswordValidationMode="Custom" 25 customUserNamePasswordValidatorType="TimeSynchronizeHttpsServer.CustomUserNameValidator,TimeSynchronizeHttpsServer"/> 26 </serviceCredentials> 27 </behavior> 28 </serviceBehaviors> 29 </behaviors> 30 <bindings> 31 <wsHttpBinding> 32 <binding name="securityMessageBinding"> 33 <security mode="TransportWithMessageCredential"> 34 <transport clientCredentialType="Basic"/> 35 <message clientCredentialType="UserName"/> 36 </security> 37 </binding> 38 </wsHttpBinding> 39 </bindings> 40 <services> 41 <service name="TimeSynchronizeHttpsServer.TimeSynchronizeService" behaviorConfiguration="securityBehavior"> 44 <endpoint address="https://127.0.0.1:12218/TimeSynchronize" 45 binding="wsHttpBinding" bindingConfiguration="securityMessageBinding" 46 contract="TimeSynchronizeHttpsServer.ITimeSynchronizeService"> 47 <identity> 48 <dns value="localhost" /> 49 </identity> 50 </endpoint> 51 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 52 <host> 53 <baseAddresses> 54 <add baseAddress="http://localhost:8733/Design_Time_Addresses/TimeSynchonizeHttpsServer/TimeSynchronizeService/" /> 55 </baseAddresses> 56 </host> 57 </service> 58 </services> 59 </system.serviceModel> 60 </configuration>
其中serviceCredentials節點中添加了serviceCertificate節點,該節點用來指定使用的證書。findValue,此attribute指定的是(2)中命令行中CN=右側的字符。userNameAuthentication制定了自定義的Validator。binding節點中使用了wsHttpBinding,並將傳輸的加密方式指定爲TransportWithMessageCredential,並制定Message的受權方式爲UserName,Transport的受權方式爲Basic。endpoint的地址須要使用https協議做爲基地址的頭部。spa
(4) 將服務端應用程序綁定到SSL證書上命令行
若是你的WCF的承載方式爲self-host(所謂self-host方式,指將WCF服務host在一個windows外殼中,包括winform、wpf、windowService。這種方式是相對於IIS承載來講的,IIS承載方式網上介紹的例子已經不少了,這篇文章主要介紹self-host方式。),須要手動將你的外殼程序綁定到SSL證書上。
首先須要使用(2)中的方式在LocalMachine中創建一個證書,注意,必定是LocalMachine中。而後,使用下面的命令行代碼,將你的服務端外殼程序綁定到SSL證書上。
1 netsh http add sslcert ipport=0.0.0.0:12218 certhash=1dca86867481b22c8f15a134df62af649cc3343a clientcertnegotiation=enable appid={02639d71-0935-35e8-9d1b-9dd1a2a34627}
其中,ipport的值中的0.0.0.0表明本地地址,冒號後面表明端口;certhash的值爲證書的thumbPrint值,怎麼找到這個值呢?follow this article吧,哈哈,英文的,z正好提升一下你的英語水平,哈哈。appid中的值是程序的guid,在項目屬性的assemblyInfo中能夠找到。
2. 客戶端
(1) 實現CertificateValidator
這個是在第二篇文章中沒有的,這個Validator幹啥用的呢。這個東西是由於咱們的證書都是本身頒發給給本身的,因此在安全性上存在一些問題,若是咱們用根證書頒發機構頒發的證書,讓這個Validator見鬼去吧,哈哈。
1 class CertificateValidator 2 { 3 public static void SetCertificatePolicy ( ) 4 { 5 ServicePointManager.ServerCertificateValidationCallback 6 += RemoteCertificateValidate; 7 } 8 private static bool RemoteCertificateValidate ( object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error ) 9 { 10 System.Console.WriteLine ( "Warning, trust any certificate" ); 11 return true; 12 } 13 }
在客戶端調用代碼時,調用客戶端的Contract以前,調用CertificateValidator.SetCertificatePolicy()方法。
(2) 完成客戶端配置文件
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <startup> 4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 5 </startup> 6 <appSettings> 7 <add key="username" value="username"/> 8 <add key="password" value="password"/> 9 </appSettings> 10 <system.serviceModel> 11 <bindings> 12 <wsHttpBinding> 13 <binding name="securityMixedBinding"> 14 <security mode="TransportWithMessageCredential"> 15 <transport clientCredentialType="Basic"/> 16 <message clientCredentialType="UserName"/> 17 </security> 18 </binding> 19 </wsHttpBinding> 20 </bindings> 21 <client> 22 <endpoint address="https://127.0.0.1:12218/TimeSynchronize" 23 binding="wsHttpBinding" bindingConfiguration="securityMixedBinding" 24 contract="ITimeSynchronizeService" 25 name="DefaultBinding_ITimeSynchronizeService_ITimeSynchronizeService" /> 26 </client> 27 </system.serviceModel> 28 </configuration>
須要注意的是,binding節點須要與服務端配置文件中的binding配置相同。endpoint的地址與service相同,都要採用https基地址。
(3) 實現客戶端調用代碼
1 private const string USERNAME = "userName"; 2 private const string PASSWORD = "password"; 3 4 static void Main ( string[] args ) 5 { 6 var proxy = new TimeSynchronizeServiceClient ( ); 7 var userName = ConfigurationManager.AppSettings[USERNAME]; 8 var password = ConfigurationManager.AppSettings[PASSWORD]; 9 proxy.ClientCredentials.UserName.UserName = userName; 10 proxy.ClientCredentials.UserName.Password = password; 11 CertificateValidator.SetCertificatePolicy ( ); 12 var time = proxy.GetTime ( ); 13 var builder = new StringBuilder ( ); 14 builder.Append ( "Server time is:" ).Append ( " " ).Append ( time ); 15 var message = builder.ToString ( ); 16 Console.WriteLine ( message ); 17 Console.ReadKey ( ); 18 }
在調用客戶端的Contract以前,須要調用CertificateValidator.SetCertificatePolicy()方法。
OK,打完收工。