[WCF安全3]使用wsHttpBinding構建基於SSL與UserName受權的WCF應用程序

      上一篇文章中介紹瞭如何使用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,打完收工。

相關文章
相關標籤/搜索