WCF简单教程(9) 安全 - 自定义认证

简介:

第九篇:WCF安全 - 自定义认证

接着上一篇,我们尝试一下用自定义用户名密码的方式来做安全认证,这样就不用受制于Windows的用户系统了。

首先需要说明的是,使用自定义用户名密码时,由于不能利用Windows用户系统的相关安全机制了,因此必须自己准备数字证书来处理数据加密。

1、准备数字证书

证书要求有可进行密钥交换的私钥,一般用makcert比较方便,自带的,也可以用OpenSSL或OpenSSL.Net一类的。本例中生成一个自签名的根证书,放入系统的受信根证书颁发机构区:

 
  1. makecert -n "CN=192.168.90.81" -b 01/01/2012 -e 01/01/2050 -r -sky exchange -sr LocalMachine -ss Root -a sha1 
  2.  
  3. 参数含义: 
  4.   -n 指定使用者为192.168.90.81,注意它必须和调用时指定的域名一致 
  5.   -b 起始日期为2012-1-1 
  6.   -e 失效日期为2050-1-1 
  7.   -r 自签名 
  8.   -sky exchange 指定是密钥交换型而不是签名型 
  9.   -sr LocalMachine 存入本地计算机 
  10.   -ss Root 存入受信任根证书颁发机构区 
  11.   -a sha1 使用SHA1签名 


2、服务端 

服务端要修改几处,首先是配置文件App.config:

 
  1. <?xml version="1.0" encoding="utf-8" ?> 
  2. <configuration> 
  3.   <system.serviceModel> 
  4.     <services> 
  5. <!--在上一篇的基础上加了behaviorConfiguration,内容见后--> 
  6.       <service name="Server.DataProvider" behaviorConfiguration="tcpBehavior"> 
  7.         <endpoint address="" binding="netTcpBinding" contract="Server.IData" bindingConfiguration="tcpBinding" /> 
  8.         <host> 
  9.           <baseAddresses> 
  10.             <add baseAddress="net.tcp://localhost:8081/wcf" /> 
  11.           </baseAddresses> 
  12.         </host> 
  13.       </service> 
  14.     </services> 
  15.  
  16.     <bindings> 
  17.       <netTcpBinding> 
  18.         <binding name="tcpBinding"> 
  19.           <security mode="Message"> 
  20. <!--与上一篇相比,认证类型从Windows改成了UserName--> 
  21.             <message clientCredentialType="UserName" /> 
  22.           </security> 
  23.         </binding> 
  24.       </netTcpBinding> 
  25.     </bindings> 
  26.  
  27. <!--这是新加的节,用于指定用户名密码的验证方式--> 
  28.     <behaviors> 
  29.       <serviceBehaviors> 
  30. <!--注意这个name是被前面使用的--> 
  31.         <behavior name="tcpBehavior"> 
  32.           <serviceCredentials> 
  33. <!--指定验证方式为Custom,表示自定义,既然是自定义的,就要指出用哪个类进行用户名密码验证,这里指定了Server程序集中的Server.Validator类,注意这里类完整名称的写法-->
  34.             <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Server.Validator, Server" /> 
  35. <!--指定用于数据加密的证书,LocalMachine表示本地计算机,Root表示受信任根证书颁发机构,192.168.90.81是证书标题(因为做证书时没指定标题,所以使用者默认就是标题),FindBySubjectName表示按标题查找-->
  36.             <serviceCertificate storeLocation="LocalMachine" storeName="Root" findValue="192.168.90.81" x509FindType="FindBySubjectName" /> 
  37.          </serviceCredentials> 
  38.         </behavior> 
  39.       </serviceBehaviors> 
  40.     </behaviors> 
  41.   </system.serviceModel> 
  42. </configuration> 

接下来是自定义的验证类,增加一个Validator类,它要继承System.IdentityModel.Selector.UserNamePasswordValidator基类。

 
  1. using System; 
  2. using System.IdentityModel.Selectors; 
  3. using System.ServiceModel; 
  4.  
  5. namespace Server 
  6.     public class Validator : UserNamePasswordValidator 
  7.     { 
  8.         //重写Validate方法,这里简化处理,直接写死用户名密码,实际应用中应结合DB、配置文件等来做验证 
  9.         public override void Validate(string userName, string password) 
  10.         { 
  11.             if(!string.Equals(userName, "root") || !string.Equals(password, "pass")) 
  12.                 throw new Exception("Access Denied"); 
  13.         } 
  14.     } 

最后我们还要小改一下契约接口的实现类,因为之前我们用WindowIdentity来识别登录用户,换用自定义用户名密码后,它不管用了,所以新的实现类是这样的:

 
  1. using System; 
  2. using System.ServiceModel; 
  3.  
  4. namespace Server 
  5.     [ServiceBehavior] 
  6.     public class DataProvider : IData 
  7.     { 
  8.         public string SayHello() 
  9.         { 
  10.          //变化不大,用PrimaryIdentity来代替WindowIdentity 
  11.             return string.Format("Hello {0}", OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name); 
  12.         } 
  13.     } 

OK,运行一下,应该能正常启动,如果失败,仔细看一下提示信息,一般都是证书问题。


3、客户端

变化不大,先来看配置文件App.config:

 
 
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <client>  
  5.        <endpoint binding="netTcpBinding" contract="Server.IData" address="net.tcp://192.168.90.81:8081/wcf" name="DataProvider" bindingConfiguration="tcp" />  
  6.     </client>  
  7.  
  8.     <bindings>  
  9.       <netTcpBinding>  
  10.         <binding name="tcp">  
  11.           <security mode="Message">  
  12. <!--只有此处把Windows改成了UserName,和服务端对应--> 
  13.             <message clientCredentialType="UserName" />  
  14.           </security>  
  15.         </binding>  
  16.       </netTcpBinding>  
  17.     </bindings>  
  18.   </system.serviceModel>  
  19. </configuration>  

然后是调用时用户名密码的传递方式变了一点:

 
 
  1. using System;  
  2. using System.ServiceModel;  
  3. using System.ServiceModel.Channels;  
  4.   
  5. namespace Client  
  6. {  
  7.     class Program  
  8.     {  
  9.         static void Main(string[] args)  
  10.         {  
  11.             //创建一个ChannelFactory,指定使用名为DataProvider的配置  
  12.             var factory = new ChannelFactory<Server.IData>("DataProvider");  
  13.   
  14.             //指定用户名、密码,和前一篇的区别是把Windows换成了UserName 
  15.             factory.Credentials.UserName.UserName = "root"
  16.             factory.Credentials.UserName.Password = "pass"
  17.   
  18.             //创建Channel,并调用SayHello方法  
  19.             var proxy = factory.CreateChannel();  
  20.             Console.WriteLine(proxy.SayHello());  
  21.             ((IChannel)proxy).Close();  
  22.         }  
  23.     }  
  24. }  


一切就绪,运行一下吧,应该能看到“Hello root”。如果用户名密码错误,会收到Exception。

如果服务端启动失败,请检查:

   ◇ 证书是否有可交换的密钥
   
◇ 证书是否正确导入了系统
   
◇ 按服务端App.config中指定的证书查找方式是否可找到证书
   
◇ 指定的自定义验证类名称是否错误

如果客户端访问失败,请检查: 

   ◇ 是否提供了正确的用户名密码
   ◇ 服务端证书有效期是否合法
   
◇ 服务端证书的证书链是否完整
   
◇ 客户端访问时使用的域名/IP是否与服务端证书的使用者一致

OK,安全问题就讲到这里吧,既然是简单教程,就不继续深入了。

 


     本文转自 BoyTNT 51CTO博客,原文链接:http://blog.51cto.com/boytnt/818443,如需转载请自行联系原作者


相关文章
WCF基础教程(四)——数据契约实现传送自定义数据类型
WCF基础教程(四)——数据契约实现传送自定义数据类型
117 0
|
安全 网络协议 网络安全
WCF安全3-Transport与Message安全模式
WCF安全3-Transport与Message安全模式
126 0
WCF安全3-Transport与Message安全模式
|
存储 算法 安全
WCF安全2-非对称加密
WCF安全2-非对称加密
155 0
WCF安全2-非对称加密
|
安全 数据安全/隐私保护
WCF安全1-开篇
WCF安全1-开篇
127 0
WCF安全1-开篇
|
安全 数据安全/隐私保护 Windows
(WCF初体验)WCF的认证和消息保护
最近做WCF开发,有个需求是在服务端做认证,网上查资料了解到可以用UserName和Password 来做认证,只需要写好配置文件和在服务端写好验证类就行了,但是网上普遍的博文都是需要用证书,而我自己却只想做个简单的认证不想用证书来增加传输的安全性。
1293 0
|
前端开发
WCF更新服务引用报错的原因之一
WCF更新服务引用报错的原因之一
|
C# 数据安全/隐私保护
c#如何创建WCF服务到发布(SqlServer版已经验证)
c#如何创建WCF服务到发布(SqlServer版已经验证)
70 0