[WCF安全2]使用wsHttpBinding构建UserName授权的WCF应用程序,非SSL

  上一篇文章中介绍了如何使用basicHttpBinding构建UserName授权的WCF应用程序,本文将为您介绍如何使用wsHttpBinding构建非SSL的UserName安全授权的WCF应用程序。

  与上篇文章一样,同样将该示例分为服务端与客户端介绍。

  1. 服务端

  (1) 实现CustomUserNameValidator

  与上篇文章一样,需要首先实现CustomUserNameValidator,如果还不知道如何生成CustomUserNameValidator,请参考上一篇文章

 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) 注册服务端证书

  这个环节是在上一篇文章中没有的,后文中要介绍到,我们使用了Message的方式加密消息内容,因此,我们需要将传输内容加密,因此需要使用证书进行加密。我们使用微软自带的"makecert.exe"命令行工具向currentUser注册一个证书。使用Visual Studio自带的命令行工具执行下面命令行。

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   <appSettings>
 4     <add key="username" value="username"/>
 5     <add key="password" value="password"/>
 6   </appSettings>
 7   <startup>
 8     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
 9   </startup>
10   <system.serviceModel>
11     <behaviors>
12       <serviceBehaviors>
13         <behavior name="securityBehavior">
14           <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
15           <serviceDebug includeExceptionDetailInFaults="true" />
16           <serviceCredentials>
17             <serviceCertificate
18               findValue="ServerCert"
19               x509FindType="FindBySubjectName"
20               storeLocation="CurrentUser"
21               storeName="My"/>
22             <userNameAuthentication
23               userNamePasswordValidationMode="Custom"
24               customUserNamePasswordValidatorType="TimeSynchronizeServer.CustomUserNameValidator,TimeSynchronizeServer"/>
25           </serviceCredentials>
26         </behavior>
27       </serviceBehaviors>
28     </behaviors>
29     <bindings>
30       <wsHttpBinding>
31         <binding name="securityMessageBinding">
32           <security mode="Message">
33             <message clientCredentialType="UserName"/>
34           </security>
35         </binding>
36       </wsHttpBinding>
37     </bindings>
38     <services>
39       <service name="TimeSynchronizeServer.TimeSynchronizeService"
40                behaviorConfiguration="securityBehavior">
41         <endpoint address="http://127.0.0.1/12216/TimeSynchronize"
42                   binding="wsHttpBinding" bindingConfiguration="securityMessageBinding"
43                   contract="TimeSynchronizeServer.ITimeSynchronizeService">
44           <identity>
45             <dns value="ServerCert" />
46           </identity>
47         </endpoint>
48         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
49         <host>
50           <baseAddresses>
51             <add baseAddress="http://localhost:8733/Design_Time_Addresses/TimeSynchronizeServer/TimeSynchronizeService/" />
52           </baseAddresses>
53         </host>
54       </service>
55     </services>
56   </system.serviceModel>
57 </configuration>

  其中serviceCredentials节点中添加了serviceCertificate节点,该节点用来指定使用的证书。findValue,此attribute指定的是(2)中命令行中CN=右侧的字符。userNameAuthentication制定了自定义的Validator。binding节点中使用了wsHttpBinding,并将传输的加密方式指定为Message,并制定UserName为授权方式。

  2. 客户端

  (1) 完成客户端配置文件

 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="securityMessageBidning">
14           <security mode="Message">
15             <message clientCredentialType="UserName"/>
16           </security>
17         </binding>
18       </wsHttpBinding>
19     </bindings>
20     <client>
21       <endpoint address="http://127.0.0.1/12216/TimeSynchronize/"
22           binding="wsHttpBinding" bindingConfiguration="securityMessageBidning"
23           contract="ITimeSynchronizeService" name="DefaultBinding_ITimeSynchronizeService_ITimeSynchronizeService">
24         <identity>
25           <dns value="ServerCert"/>
26         </identity>
27       </endpoint>
28     </client>
29   </system.serviceModel>
30 </configuration>

  需要注意的是,binding节点需要与服务端配置文件中的binding配置相同。特别要注意的是,endpoint节点中的identity节点中的dns的value需要与证书名称相同,否则会抛出一个异常,具体问题我还没搞明白,不过搜索了一下,发现这样能够解决问题。

  (2) 完成客户端调用代码

 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     proxy.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
12                              X509CertificateValidationMode.None;  
13     var time = proxy.GetTime ( );
14     var builder = new StringBuilder ( );
15     builder.Append ( "Server time is:" ).Append ( " " ).Append ( time );
16     var message = builder.ToString ( );
17     Console.WriteLine ( message );
18    Console.ReadKey ( );
19 }

OK,大功告成!

下一篇:[WCF安全3]使用wsHttpBinding构建基于SSL与UserName授权的WCF应用程序

posted @ 2013-08-26 21:18  yafeya  阅读(314)  评论(0编辑  收藏  举报