zoukankan      html  css  js  c++  java
  • 【转】x.509证书在WCF中的应用(CS篇)

    【转自】x.509证书在WCF中的应用(CS篇)

    为什么要用x.509证书?
    WCF的服务端和客户端之间,如 果不作任何安全处理(即服务端的<security mode="None">),则所有传输的消息将以明文方式满天飞,在internet/intranet环境下无疑是很不安全的,这就是用证书的 目的。(当然WCF还有其它安全机制,比如最常见的UserName方式,但通常每次都要从数据库读取用户名/密码信息进行验证,比较麻烦,开销也大,个 人觉得还是证书最为方便)--关于x.509证书

    的基本知识,可参见http://www.cnblogs.com/yjmyzz/archive/2008/08/19/1271171.html

    大致原理(个人理解,可能不太准确):
    正确设置服务端与客户端证书后,WCF的服务端启动时,需要利用服务端证书验证,如果验证通过将正常启动,否则报异常,同时客户端调用服务端方法时,也需要提供客户端证书,服务端接受到客户端证书后,验证客户端证书的有效性,如果通过,则允许客户端正常调用。

    下面将逐步讲解如何使用:

    1.制作证书

    先进入到vs2008的命令行状态,即:
    开始-->程序-->Microsoft Visual Studio 2008-->Visual Studio Tools-->Visual Studio 2008 命令提示

    键入:

    makecert -r -pe -n "CN=MyServer" -ss My -sky exchange

    解释一下:makecert.exe是一个专门用来制作证书的小工具,上面一行的意思就是制作一个CN=MyServer的服务器证书,默认存储在CurrentUser"My这个位置,同时这个证书标识为可导出。(详细的

    MakeCert参数可参见http://msdn.microsoft.com/zh-cn/bfsktky3(vs.80).aspx)

    再输入:

    makecert -r -pe -n "CN=MyClient" -ss My -sky exchange

    生成客户端证书,证书生成好以后,可以在IE里查看到,IE-->工具-->Internet选项-->内容-->证书

    同时如何管理已经安装的证书,可参见http://www.cnblogs.com/yjmyzz/archive/2008/08/20/1272128.html

    2.wcf服务端

    vs.net2008启动后,新建一个控制台应用程序-->(右击)添加-->新建项-->WCF服务-->命名为MyService.cs-->保存

    保存后,系统会自动生成一个接口文件IMyService.cs

    二个文件的内容如下:
    IMyService.cs

    using System;  
    using System.ServiceModel;

    namespace Server
    {
        
    // 注意: 如果更改此处的接口名称 "IMyService",也必须更新 App.config 中对 "IMyService" 的引用。
        [ServiceContract]
        
    public interface IMyService
        {
            [OperationContract]
            
    string Test();

        }
    }


    MyService.cs

    using System; 
    using System.ServiceModel;
    namespace Server
    {
        
    // 注意: 如果更改此处的类名 "MyService",也必须更新 App.config 中对 "MyService" 的引用。
        public class MyService : IMyService
        {
            
    public string Test()
            {
                Console.WriteLine(
    "服务端输出:"n" + ServiceSecurityContext.Current.PrimaryIdentity.AuthenticationType);
                Console.WriteLine(ServiceSecurityContext.Current.PrimaryIdentity.Name);
                
    return "服务端时间:" + DateTime.Now.ToString(); 
            }
        }
    }

    再来新建一个cs文件:CustomX509CertificateValidator.cs
    内容先贴在下面

    using System;
    using System.Security.Cryptography.X509Certificates;
    using System.IdentityModel.Tokens;
    using System.IdentityModel.Selectors;

    namespace Server
    {
        
    public class CustomX509CertificateValidator : X509CertificateValidator
        {
            
    public override void Validate(X509Certificate2 certificate)
            {
                Console.WriteLine(certificate.Subject);
                Console.WriteLine(certificate.Thumbprint); 
                
    if (certificate.Thumbprint != "3E4D4B64A90810B6CFF9B1DD2390D8C9488747BF")
                    
    throw new SecurityTokenException("Certificate Validation Error!");
            }
        }
    }

    注意:项目必须先添加对System.IdentityModel的引用

    解释一下:
    这个文件的用户是:客户端要调用服务端方法,并提供客户端证书时,用来验证客户端证书的有效性。注意里面的if (certificate.Thumbprint != "3E4D4B64A90810B6CFF9B1DD2390D8C9488747BF")这一句,大家调试的时候,里面的 3E4D4B64A90810B6CFF9B1DD2390D8C9488747BF要换成你自己的客户端证书的信息(每一个证书对应的这一串字符都是唯 一的),可通过在IE浏览器里,查看MyClient证书的详细信息得到,见下图:


    同时注意配置文件App.Config,内容如下

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        
    <system.serviceModel>
            
    <behaviors>
                
    <serviceBehaviors>
                    
    <behavior name="Server.MyServiceBehavior">
                      
    <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8080" />
                      
    <serviceDebug includeExceptionDetailInFaults="true" />
                      
    <serviceCredentials>
                        
    <clientCertificate>
                          
    <authentication certificateValidationMode="Custom" customCertificateValidatorType="Server.CustomX509CertificateValidator,Server"/>
                        
    </clientCertificate>
                        
    <serviceCertificate findValue="MyServer" storeLocation="CurrentUser"
                          x509FindType
    ="FindBySubjectName" />
                      
    </serviceCredentials>
                    
    </behavior>
                
    </serviceBehaviors>
            
    </behaviors>
          
    <bindings>
            
    <netTcpBinding>
              
    <binding name="NewBinding0">
                
    <security mode="Transport">
                  
    <transport clientCredentialType="Certificate" />
                
    </security>
              
    </binding>
            
    </netTcpBinding>
          
    </bindings>
            
    <services>
                
    <service behaviorConfiguration="Server.MyServiceBehavior" name="Server.MyService">
                    
    <endpoint address="net.tcp://localhost:8081" binding="netTcpBinding" contract="Server.IMyService" bindingConfiguration="NewBinding0"/>              
                
    </service>
            
    </services>
        
    </system.serviceModel>
    </configuration>

    解释一下:
    <authentication certificateValidationMode="Custom" customCertificateValidatorType="Server.CustomX509CertificateValidator,Server"/></clientCertificate>
    这一行的意思就是通知WCF服务端,验证客户端证书的模式为自定义,验证时调用Server.CustomX509CertificateValidator这个类来完成验证

    <serviceCertificate findValue="MyServer" storeLocation="CurrentUser" x509FindType="FindBySubjectName" />
    这一行的意思是WCF服务端验证证书时,到CurrentUser这个位置查询CN=MyServer的证书

    最后在Program.cs里启用WCF,内容如下:

    using System;  
    using System.ServiceModel;

    namespace Server
    {
        
    class Program
        {
            
    static void Main(string[] args)
            {
                ServiceHost host 
    = new ServiceHost(typeof(MyService));
                host.Open();
                Console.ReadKey();
            }
        }
    }

    build一下,如果编译无错的话,服务端完工,可以运行一下,将弹出一个DOS命令窗口(不过什么输出也没有),只要不报错,就表明Ok了,先不要急着关,尝试浏览一下:

    http://localhost:8080/(这个地址哪里来的?回头看下App.config,里面有一行<serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8080/" />,呵呵,明白了吧) 正常的话,应该类似下图所示:

    3.客户端调用

    下面生成服务端的代理和配置文件,客户端开发将用到这二个文件,同样先进入vs2008的命令行状态,输入:

    svcutil.exe http://localhost:8080/ /d:c:"123"

    注意:输入这一行命令的时候,请确保服务端程序正在运行。这一句的意思就是在c:"123"目录下输出WCF的代理文件和配置文件

    打开vs.net2008,再新建一个控制台应用程序,可以命名为Client

    把c:"123"下生成的二个文件MyService.cs,output.config添加到Client项目中,同时将output.config改名为App.Config

    Progam.cs代码内容如下:

    using System; 
    namespace Client
    {
        
    class Program
        {
            
    static void Main(string[] args)
            {
                
    using (MyServiceClient client = new MyServiceClient())
                {
                    Console.WriteLine(
    "客户端输出:");
                    Console.WriteLine(client.Test());
                } 
                Console.ReadKey();
            }
        }
    }

    同时,参考下面的内容手动修改一下App.Config文件

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        
    <system.serviceModel>
          
    <behaviors>
            
    <endpointBehaviors>
              
    <behavior name="NewBehavior">
                
    <clientCredentials>
                  
    <clientCertificate findValue="MyClient" x509FindType="FindBySubjectName"/>
                  
    <serviceCertificate>
                    
    <authentication certificateValidationMode="None" />
                  
    </serviceCertificate>
                
    </clientCredentials>
              
    </behavior>
            
    </endpointBehaviors>
          
    </behaviors>
          
    <bindings>
                
    <netTcpBinding>
                    
    <binding name="NetTcpBinding_IMyService" closeTimeout="00:01:00"
                        openTimeout
    ="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                        transactionFlow
    ="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                        hostNameComparisonMode
    ="StrongWildcard" listenBacklog="10"
                        maxBufferPoolSize
    ="524288" maxBufferSize="65536" maxConnections="10"
                        maxReceivedMessageSize
    ="65536">
                        
    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                            maxBytesPerRead
    ="4096" maxNameTableCharCount="16384" />
                        
    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                            enabled
    ="false" />
                        
    <security mode="Transport">
                            
    <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
                            
    <message clientCredentialType="Windows" />
                        
    </security>
                    
    </binding>
                
    </netTcpBinding>
            
    </bindings>
            
    <client>
                
    <endpoint address="net.tcp://localhost:8081/" binding="netTcpBinding"
                    bindingConfiguration
    ="NetTcpBinding_IMyService" contract="IMyService"
                    name
    ="NetTcpBinding_IMyService" behaviorConfiguration="NewBehavior">
                    
    <identity>
                        
    <dns value="MyServer" />
                    
    </identity>
                
    </endpoint>
            
    </client>
        
    </system.serviceModel>
    </configuration>

    主要是增加了一个节点
    <behaviors>
            <endpointBehaviors>
              <behavior name="NewBehavior">
                <clientCredentials>
                  <clientCertificate findValue="MyClient" x509FindType="FindBySubjectName"/>
                  <serviceCertificate>
                    <authentication certificateValidationMode="None" />
                  </serviceCertificate>
                </clientCredentials>
              </behavior>
            </endpointBehaviors>
          </behaviors>

    上面红色的行,就是表明客户端调用时,将用MyClient证书来验证

    同时<endpoint address="net.tcp://localhost:8081/" binding="netTcpBinding"
                    bindingConfiguration="NetTcpBinding_IMyService" contract="IMyService"
                    name="NetTcpBinding_IMyService" behaviorConfiguration="NewBehavior">这一句,增加了behaviorConfiguration="NewBehavior"

    好了,Build一下,没有问题的话,开发完成


    4.测试:
    先启动服务端,再启动客户端,运行结果如下:

    (转贴请注明来自"菩提树下的杨过") http://www.cnblogs.com/yjmyzz/archive/2008/08/20/1272550.html

    注意服务端server.exe输出的信息中3E4D4B64A90810B6CFF9B1DD2390D8C9488747BF与客户端证书完全吻合

    最后来谈谈分发问题,上面这一系列测试都是在同一台机器完成的,客户端总不可能总是跟服务端在一台机器上,这个好办,在IE里把MyClient证书导出,注意导出时要选择"是,导出私钥",然后把导出的pfx文件连同客户端程序一起分发到目标客户机即可,这里要注意几点:

    a.客户端上的App.config里,要把<endpoint address="net.tcp://localhost:8081/" 中的localhost换成服务端的Ip地址
    b.注意防火墙参数设置(本例中,即要把tcp:8081端口打开)

  • 相关阅读:
    游戏开发热门技术浅析
    SpringMVC文件分片上传,断点续传
    浏览器文件分片上传,断点续传
    网页文件分片上传,断点续传
    Web文件分片上传,断点续传
    JavaScript文件分片上传,断点续传
    js文件分片上传,断点续传
    html5文件分片上传,断点续传
    vue文件分片上传,断点续传
    csharp文件分片上传,断点续传
  • 原文地址:https://www.cnblogs.com/gengaixue/p/1394800.html
Copyright © 2011-2022 走看看