none
WCF分布式安全开发实践(10):消息安全模式之自定义用户名密码:Message_UserNamePassword_WSHttpBinding RRS feed

  • 常规讨论

  • 原文地址:WCF分布式安全开发实践(10):消息安全模式之自定义用户名密码:Message_UserNamePassword_WSHttpBinding
    WCF分布式安全开发实践(10):消息安全模式之自定义用户名密:Message_UserNamePassword_WSHttpBinding 
        文章主要是消息安全模式下的UserNamePassword身份验证方式,基于WSHttpBinding绑定协议。主要内容:制作证书、服务验证代码、服务端配置、客户端配置、总结等5个部分。依次是最重要的5个步骤。
        下面我们来介绍具体的内容,首先就是要制作一个服务端使用的证书,用来建立TLS传输安全层会话使用。
    【1】制作证书:
     (1)使用makecert 工具:Microsoft Visual Studio 2008-->Visual Studio Tools-->Visual Studio 2008 命令提示行。输入:makecert -r -pe -n "CN=FrankWCFServer" -ss My -sky exchange
     (2) 打开浏览器---->Internet 选项----->内容----->证书----->个人,默认是保存到当前用户CurrentUser,你会看到刚才制作的证书。如图:

      也可以使用MMC建立证书控制单元,里查看证书的信息:
      开始--运行--MMC--控制台--添加删除单元--证书--当前用户和计算机各添加一个。能查看和管理CurrentUser和LocalMachine的所有证书。如图:
     
    (3)如果证书不可以使用,可以参考设置证书为可信任的步骤:WCF分布式开发常见错误(22):The caller was not authenticated...如何在XP系统为WCF设置可信任的证书有介绍。
    【2】服务验证代码:
        证书制作完整以后,就需要来实现自定义用户名和密码的验证程序。这里要重写MyUserNamePasswordValidator类的Validate(string userName, string password)方法。具体代码如下:
    public class MyUserNamePasswordValidator : UserNamePasswordValidator 
        { 
            
    public override void Validate(string userName, string password) 
            {
                
    if (userName != "FrankXuLei" || password != "12345678")
                {
                    Console.WriteLine(
    "UserNamePasswordValidatation is failed !:{0}", userName);
                    
    throw new SecurityTokenException("Unknown Username or Password"); 
                }
                
    else
                {
                    Console.WriteLine(
    "UserNamePasswordValidatation is sucessfully !:{0}", userName);
                }
            } 
        } 
       这里假定用户名是FrankXuLei,密码是123456.如果不对就直接抛出异常,验证失败,实际应用我们可以到身份验证数据库查询数据,来判定用户名和密码的有效性。
    【3】服务端配置:
      托管宿主的配置较为复杂,除了要配置服务端证书,还要配置绑定的安全模式,以及自定义身份验证程序集。
    (1)配置服务端证书:
          设置刚才制作的证书,配置文件如下:
    <serviceCertificate  x509FindType="FindBySubjectName" findValue="WCFServerCertificate" storeLocation="CurrentUser"/>
      根据主题名称到当前用户的查找证书。还可以根据证书指纹等方式查找。
    (2)配置绑定的安全模式:
        这里使用的绑定要支持消息安全模式的自定义用户名和密码,可以从第一篇文章WCF分布式安全开发实践(0):文章和代码结构规划介绍WCF分布式开发步步为赢(14):WCF安全编程--基本概念找到适合的绑定协议。这里就以WSHTTPBinding为例子。配置代码如下:
     <wsHttpBinding>
            
    <binding  name="MessageAndUserName"   >
              
    <security  mode="Message">
                
    <transport clientCredentialType="None"/>
                
    <message clientCredentialType="UserName"/>
              
    </security>
            
    </binding>
          
    </wsHttpBinding>
       消息安全模式启用UserName验证方式。
    (3)配置自定义身份验证程序集:
       下面我们来配置一下自定义实现的身份验证程序集,配置代码如下:
    <userNameAuthentication userNamePasswordValidationMode="Custom"    customUserNamePasswordValidatorType="WCFService.MyUserNamePasswordValidator,WCFService" />
              
         这里要注意,前面是命名空间和类,逗号后面就是服务名称。
     (4)服务代码:
       这里的服务代码很简单,string HelloMessageSecurity(string name);会根据传入的名称来答应消息。为了测试加了打印时间,代码如下:
     //1.服务契约
        [ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
        
    public interface IWCFService
        {
            
    //操作契约
            [OperationContract]
            
    string HelloMessageSecurity(string name);

        }
        
    //2.服务类,继承接口。实现服务契约定义的操作
        
    //2.服务类.单调服务
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
        
    public class WCFService : IWCFService
        {
            
    //实现接口定义的方法
            public string HelloMessageSecurity(string name)
            {
                
    //提供方法执行的上下文环境
                OperationContext context = OperationContext.Current;
                
    //获取传进的消息属性
                MessageProperties properties = context.IncomingMessageProperties;
                
    //获取消息发送的远程终结点IP和端口
                RemoteEndpointMessageProperty endpoint = properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
                Console.WriteLine(
    string.Format("Hello {0},You are  from {1}:{2}", name, endpoint.Address, endpoint.Port));
                
    return string.Format("Hello {0},You are  from {1}:{2}", name, endpoint.Address, endpoint.Port);
            }
        }
    【4】客户端配置:
        运行托管宿主,客户端添加服务引用,直接生成相关代码文件。我们直接添加代码测试,这里要测试两种情况,正确的用户名和密码,错误的用户名或者密码。前者成功。客户端测试代码如下:
    using (ClientProxy.WCFServiceClient ClientProxy = new ClientProxy.WCFServiceClient("WSHttpBinding_IWCFService"))
                {
                    
    string strUserName = "Frank Xu Lei ";
                    
    string strMessage = "";
                    
    //通过代理调用SayHelloToUser服务
                    ////正确测试密码
                    ClientProxy.ClientCredentials.UserName.UserName = "FrankXuLei";
                    ClientProxy.ClientCredentials.UserName.Password 
    = "12345678";              
                    
    //Console.WriteLine(strMessage);
                    
    //错误测试密码

                    
    //ClientProxy.ClientCredentials.UserName.UserName = "FrankXuLei";
                    
    //ClientProxy.ClientCredentials.UserName.Password = "88888888";
                    
    //strMessage = wcfServiceProxy.HelloMessageSecurity(strUserName);
                    strMessage = ClientProxy.HelloMessageSecurity(strUserName);
                    Console.WriteLine(strMessage);
                }
                
    //For Debug
                Console.WriteLine("Press any key to continue");
                Console.Read();
    【5】总结:
        启动托管宿主,然后启动客户端调用服务进行测试,运行结果如图:
        
     这个系列先从这个文章开始,主要是这个代码已经实现很久了,一直因为太忙没有写出文章,今天加班搞定。
    (1):使用 .NET Framework 3.5 版 或更高版本时,可将自定义用户名和密码验证程序与消息和传输安全一起使用。使用 .NET Framework 3.0 时,自定义用户名和密码验证程序只能与消息安全一起使用。
    (2):代码示例重写的 Validate 方法。如果在实际的项目里可以替换为您的自定义用户名和密码验证方案,从数据库检索用户名和密码来进行比较。你可以访问数据库或者其它的账号安全验证的数据进行验证。也是最灵活的方式之一,用户可以根据需要来定义身份验证机制。
    (3):与WSE3.0的身份验证机制略有不同的是这里要使用到证书,原因是消息安全模式下,需要使用证书来建立TLS传输安全层,是WS-Trust规范,SSL安全套接层的升级安全规范。因此需要证书。
    (4):提供本文的Demo程序的下载,
    /Files/frank_xl/6.4.WCFServiceSecurityDemoFrankXuLei_Message_UserNamePassword_WSHttpBinding.rar
       时间仓促,有不足的地方请多多包含。 欢迎大家提出意见,互相交流学习。如果程序运行相关问题可以留言或者到WCF中文论坛来交流~谢谢
    参考文章:
    1.WCF分布式开发常见错误(22):The caller was not authenticated...如何在XP系统为WCF设置可信任的证书
    2.WCF分布式开发常见错误(21):unable to open its IChannelListener.分发器未能打开侦听器
    3.http://social.microsoft.com/Forums/zh-CN/wcfzhchs/thread/e1aa7bea-90d8-41e6-b91b-7addba44f8e3
    4.WSE3.0构建Web服务安全(2):非对称加密、公钥、密钥、证书、签名的区别和联系以及X.509 证书的获得和管理,具体5.http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cptools/html/cpgrfcertificatecreationtoolmakecertexe.asp

     


    老徐的博客
    【作      者】:Frank Xu Lei
    【地      址】:http://www.cnblogs.com/frank_xl/
    【中文论坛】:微软WCF中文技术论坛
    【英文论坛】:微软WCF英文技术论坛


    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
    欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
    欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum
    2009年8月12日 4:59
    版主