博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WCF简单教程(9) 安全 - 自定义认证
阅读量:6193 次
发布时间:2019-06-21

本文共 4171 字,大约阅读时间需要 13 分钟。

第九篇: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,安全问题就讲到这里吧,既然是简单教程,就不继续深入了。

 

转载地址:http://vfuca.baihongyu.com/

你可能感兴趣的文章
JS存在性
查看>>
获取微信openid
查看>>
阿里云配置ssl证书服务遇到的几个问题和解决方法
查看>>
bzoj 4566 [Haoi2016]找相同字符——广义后缀自动机
查看>>
程序猿也爱学英语(上),有图有真相
查看>>
leetcode 237 Delete Node in a Linked List python
查看>>
(转)清华学霸演讲稿:永远不要说你已经尽力了
查看>>
[转载]获取IP
查看>>
4.ASCII码排序
查看>>
关于H5唤醒APP的功能实现
查看>>
java 判断请求来自手机端还是电脑端
查看>>
SQL SERVER的整型运算,让人大吃一惊
查看>>
掀开图片显示介绍的css效果
查看>>
SQL Server基础知识
查看>>
soket.io.js + angular.js + express.js(node.js)
查看>>
开源CMS比较
查看>>
Unity 灯光探针用法教程
查看>>
最高优先级算法——进程调度
查看>>
转载:SVN分支合并
查看>>
nginx 负载均衡5种配置方式
查看>>