最近到了新公司,leader让我研究一下WCF的传输安全机制。以前也做过WCF的应用,但是很少涉及安全方面的东西。所以,花了三天的时间研究了一下如何在WCF的应用程序中配置安全。在这个系列文章中,我会将我的一些心得分享给大家,希望对大家有所帮助。
我所做的研究主要是使用UserName的验证方式,对请求进行验证,本文主要介绍使用basicHttpBinding进行验证,后续两篇文章中将针对wsHttpBinding介绍使用http方式验证以及https(SSL)方式验证。
首先,想跟大家说明,这几篇帖子,我的重点在于如何配置WCF应用程序,使你的WCF程序能够使用UserName的安全验证;而不在于如何建立WCF应用程序,如果大家想了解关于建立WCF应用程序的相关知识,请参考MSDN相关文档。
Let's go!
我将我的应用程序分为服务端与访问端,下面让我们分别看服务端与客户端。
1. 服务端
(1) 创建CustomUserNameValidator
CustomUserNameValidator从UserNamePasswordValidator类继承,并且需要实现抽象方法Validate,可以在其中实现用户名密码验证逻辑,如果验证不成功,抛出异常。
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) 完成服务端配置文件
服务端配置文件:
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 <system.serviceModel> 7 <behaviors> 8 <serviceBehaviors> 9 <behavior name="customBehavior"> 10 <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /> 11 <serviceDebug includeExceptionDetailInFaults="true" /> 12 <serviceCredentials> 13 <userNameAuthentication 14 userNamePasswordValidationMode="Custom" 15 customUserNamePasswordValidatorType="EmployeesHost.CustomUserNameValidator, EmployeesHost"/> 16 </serviceCredentials> 17 </behavior> 18 </serviceBehaviors> 19 </behaviors> 20 <bindings > 21 <basicHttpBinding> 22 <binding name="EmployeeQueryBinding_BasicHttp"> 23 <security mode="TransportCredentialOnly"> 24 <transport clientCredentialType="Basic"/> 25 </security> 26 </binding> 27 </basicHttpBinding> 28 </bindings> 29 <services> 30 <service name="EmployeesHost.EmployeesQueryService" behaviorConfiguration="customBehavior"> 31 <!--For basic http binding endpoint--> 32 <endpoint address="http://127.0.0.1:12215/EmployeeQuery" binding="basicHttpBinding" 33 bindingConfiguration="EmployeeQueryBinding_BasicHttp" 34 contract="EmployeesHost.IEmployeesQueryService"> 35 <identity> 36 <dns value="localhost" /> 37 </identity> 38 </endpoint> 39 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 40 <host> 41 <baseAddresses> 42 <add baseAddress="http://127.0.0.1:8733/Design_Time_Addresses/EmployeesHost/EmployeesQueryService/" /> 43 </baseAddresses> 44 </host> 45 </service> 46 </services> 47 </system.serviceModel> 48 <appSettings> 49 <add key="userName" value="username"/> 50 <add key="password" value="password"/> 51 </appSettings> 52 </configuration>
需要注意的是,serviceCredentials节点中需要按照上面文件中的写法。binding节点中也需要严格按照上面文件中所写。、
(3) 完成ServiceHost启动
启动ServiceHost代码:
1 static void Main(string[] args) 2 { 3 var host = new ServiceHost(typeof(EmployeesQueryService)); 4 host.Open(); 6 Console.WriteLine("Service Host opened, press <s> to stop..."); 7 var key = Console.ReadKey(); 8 if (key.Key == ConsoleKey.S) 9 { 10 host.Close(); 11 } 12 Console.WriteLine("Press any key to quit..."); 13 Console.ReadKey(); 14 }
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 <system.serviceModel> 7 <bindings> 8 <basicHttpBinding> 9 <binding name="DefaultBinding_IEmployeesQueryService"> 10 <security mode="TransportCredentialOnly"> 11 <transport clientCredentialType="Basic"/> 12 </security> 13 </binding> 14 </basicHttpBinding> 15 </bindings> 16 <client> 17 <!--For basic http binding endpoint--> 18 <endpoint address="http://127.0.0.1:12215/EmployeeQuery/" 19 binding="basicHttpBinding" bindingConfiguration="DefaultBinding_IEmployeesQueryService" 20 contract="IEmployeesQueryService" name="DefaultBinding_IEmployeesQueryService_IEmployeesQueryService" /> 21 </client> 22 </system.serviceModel> 23 <appSettings> 24 <add key="userName" value="username"/> 25 <add key="password" value="password"/> 26 </appSettings> 27 </configuration>
注意,客户端配置文件中的binding节点,需要与服务端的binding节点写法相同。
(2) 客户端调用代码
1 var userName = ConfigurationManager.AppSettings[USERNAME_ELEMENT_NAME]; 2var password = ConfigurationManager.AppSettings[PASSWORD_ELEMENT_NAME]; 3 mProxy.ClientCredentials.UserName.UserName = userName; 4 mProxy.ClientCredentials.UserName.Password = password; 5 var data = mProxy.GetData();
OK,大功告成,运行,ok。