在实际应用中实现WCF用户密码认证

开发 开发工具
WCF用户密码认证在实际应用中是比较常用的,不过它的实现方法对于刚刚接触WCF的朋友来说还是比较困难的。在这里就向大家详细介绍这些知识。

WCF框架是一款功能强大的分布式开发框架。对于初学者来说,可能其中有些功能不太熟悉。这需要我们在不断的实践中去慢慢研究这些功能。比如WCF用户密码认证的正确使用。#t#

以前我们用WebService做分布式系统的时候,认证是个麻烦的问题,通常的做法是继承一个SoapHeader,把用户名和密码放到里面,每调用一个方法都要把用户名和密码传递给服务器端来验证 ,效率相当低,代码编写相当的麻烦,而且还不安全!

WCF支持多种认证技术,例如Windowns认证、X509证书、Issued Tokens、用户名密码认证等,在跨Windows域分布的系统中,用户名密码认证还是比较常用的,要实现用户名密码认证,就必须需要X509证书,为什么呢?因为我们需要X509证书这种非对称密钥技术来实现WCF在Message传递过程中的加密和解密,要不然用户名和密码就得在网络上明文传递!详细说明就是客户端把用户名和密码用公钥加密后传递给服务器端,服务器端再用自己的私钥来解密,然后传递给相应的验证程序来实现身份验证。

当然,做个测试程序就没有必要去申请一个X509数字签名证书了,微软提供了一个makecert.exe的命令专门用来生成测试使用的X509证书的,那我们就来建立一个测试用的证书,在cmd下输入以下命令:

makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=MyServerCert -sky exchange –pe

这个命令的意思就是创建一个测试的X509证书,这个证书放在存储位置为'Localmachine'的'My'这个文件夹下,证书主题名字叫'MyServerCert',需要更多关于makecert命令的信息请参考MSDN。

证书建立好了,我们就可以编写代码了,在VS2008下建立一个解决方案并在上面建立两个Web项目,一个是'Asp.net Web 应用程序'(客户端),一个是'WCF服务应用程序'(服务器端),我们先来编写服务器端代码,首先我们要编写自己的WCF用户密码认证逻辑,先要在WCF项目上添加引用'System.IdentityModel'然后我们建立一个新的类文件并继承自'System.IdentityModel.Selectors.UserNamePasswordValidator',然后我们重写里面的'Validate'方法来实现用户名密码认证逻辑。代码如下;

 

  1. using System;   
  2. using System.Collections.Generic;   
  3. using System.Linq;   
  4. using System.Text;   
  5. using System.IdentityModel.Selectors;   
  6. using System.IdentityModel.Tokens;   
  7. namespace ServerWcfService.CustomValidators   
  8. {   
  9. public class MyCustomValidator : 
    UserNamePasswordValidator   
  10. {   
  11. /// < summary>   
  12. /// Validates the user name and 
    password combination.   
  13. /// < /summary>   
  14. /// < param name="userName">
    The user name.< /param>   
  15. /// < param name="password">
    The password.< /param>   
  16. public override void Validate
    (string userName, string password)   
  17. {   
  18. // validate arguments   
  19. if (string.IsNullOrEmpty(userName))   
  20. throw new ArgumentNullException("userName");   
  21. if (string.IsNullOrEmpty(password))   
  22. throw new ArgumentNullException("password");   
  23. // check if the user is not xiaozhuang   
  24. if (userName != "xiaozhuang" || password != "123456")   
  25. throw new SecurityTokenException("用户名或者密码错误!");   
  26. }   
  27. }   
  28. }  

 

上面只是一个简单的WCF用户密码认证,实际应用中用户名和密码一般都保存在数据库中,如果验证不通过就抛出一个'SecurityTokenException'类型的异常;下一步我们需要配置一下服务端的webConfig文件,我的WebConfig文件Servicemodel配置节如下:

 

  1. < system.serviceModel>   
  2. < bindings>   
  3. < wsHttpBinding>   
  4. < binding name="mySecureBinding">   
  5. < security mode="Message">   
  6. < message clientCredentialType="UserName"/>   
  7. < /security>   
  8. < /binding>   
  9. < /wsHttpBinding>   
  10. < /bindings>   
  11. < services>   
  12. < service behaviorConfiguration=
    "ServerWcfService.Services.MySimple
    ServiceBehavior"
     name="ServerWcfService.
    Services.MySimpleService"
    >   
  13. < endpoint address="" binding=
    "wsHttpBinding" contract="ServerWcfService.
    ServiceContracts.IMySimpleService"
     bindingConfiguration="mySecureBinding">   
  14. < identity>   
  15. < dns value="MyServerCert"/>   
  16. < /identity>   
  17. < /endpoint>   
  18. < endpoint address="mex" binding=
    "mexHttpBinding" contract="IMetadataExchange"/>   
  19. < /service>   
  20. < /services>   
  21. < behaviors>   
  22. < serviceBehaviors>   
  23. < behavior name="ServerWcfService.
    Services.MySimpleServiceBehavior"
    > 
  24. < serviceMetadata httpGetEnabled="true"/>   
  25. < serviceDebug includeExceptionDetailInFaults="false"/>   
  26. < serviceCredentials>   
  27. < serviceCertificate findValue=
    "MyServerCert" x509FindType="FindBySubjectName" 
    storeLocation="LocalMachine" storeName="My"/>   
  28. < userNameAuthentication userNamePassword
    ValidationMode
    ="Custom" customUserName
    PasswordValidatorType
    ="ServerWcfService.
    CustomValidators.MyCustomValidator,ServerWcfService"
    />   
  29. < /serviceCredentials>   
  30. < /behavior>   
  31. < /serviceBehaviors>   
  32. < /behaviors>   
  33. < /system.serviceModel>  

 

加粗的那些是我加上去的或者在默认上修改了的。Bindings节指定了客户端提供的认证类型为'username'并在endpoint节中指定bianding配置。在dns节中修改原来的localmachine为MyServerCert,当然你也可以修改为别的,这取决于你的证书主题名称是什么。也就是上面命令中的CN=MyServerCert,接下来我们加入在serviceCredentials配置节,并在里面配置两个小节,ServiceCertificate节中指定了我们的X509证书的位置,以用来加解密message,usernameAuthentication节中指定了我们自己的WCF用户密码认证逻辑。

Sorry,忘了一件事情,就是写一个测试的服务契约并实现,写法上和无认证的写法一样,如下

  1. ServerWcfService.Service
    Contracts.IMySimpleService:   
  2. [OperationContract]   
  3. string PrintMessage
    (string message);  

 

这样,服务端的代码编写和配置就完成了,生成项目测试一下,页面显示服务已生成成功。

接下来我们开始编写客户端代码,先在客户端引用刚才生成的WCF服务,然后编写客户端代码如下:

 

  1. protected void btnPrint_Click(object 
    sender, EventArgs e)   
  2. {   
  3. TestWCFService.MySimpleServiceClient 
    client = new ClientWeb.TestWCFService.
    MySimpleServiceClient();   
  4. client.ClientCredentials.UserName.
    UserName
     = "xiaozhuang";   
  5. client.ClientCredentials.UserName.
    Password
     = "123456";   
  6. lbMessage.Text = client.PrintMessage
    (txtMessage.Text);   
  7. }  

 

 

如果你有一个真正的X509证书,那么现在的WCF用户密码认证代码就可以正常运行了。但是很不幸,我们的证书是测试用的,我们运行的时候出错:'X.509 certificate CN=MyServerCert 链生成失败。所使用的证书具有无法验证的信任链。请替换该证书或更改 certificateValidationMode。已处理证书链,但是在不受信任提供程序信任的根证书中终止',WCF无法验证测试证书的信任链,那我们要做的就是绕过这个信任验证,具体做法如下:

先要在Asp.net Web应用程序项目上添加引用'System.IdentityModel'然后我们建立一个新的类文件并继承自'System.IdentityModel.Selectors.X509CertificateValidator',然后我们重写里面的'Validate'方法来实现我们自己的X509认证逻辑,代码如下:

 

  1. using System;   
  2. using System.Configuration;   
  3. using System.IdentityModel.Selectors;   
  4. using System.IdentityModel.Tokens;   
  5. using System.Security.Cryptography.
    X509Certificates;   
  6. namespace ClientWeb.CustomX509Validator   
  7. {   
  8. /// < summary>   
  9. /// Implements the validator for X509
     certificates.   
  10. /// < /summary>   
  11. public class MyX509Validator: 
    X509CertificateValidator   
  12. {   
  13. /// < summary>   
  14. /// Validates a certificate.   
  15. /// < /summary>   
  16. /// < param name="certificate">
    The certificate the validate.< /param>   
  17. public override void Validate
    (X509Certificate2 certificate)   
  18. {   
  19. // validate argument   
  20. if (certificate == null)   
  21. throw new ArgumentNullException
    ("X509认证证书为空!");   
  22. // check if the name of the certifcate matches   
  23. if (certificate.SubjectName.Name != 
    ConfigurationManager.AppSettings["CertName"])   
  24. throw new SecurityTokenValidationException(
    "Certificated was not issued by thrusted issuer");   
  25. }   
  26. }   
  27. }  

 

你可以把Validate方法里面留空让所有的认证都通过,也可以自己定义认证逻辑,如果认证失败,就抛出'SecurityTokenValidationException'的异常,然后我们配置一下客户端的webconfig让它使用我们自己的X509认证,增加以下的配置节,并在'endpoint'节中指定behaviorConfiguration="myClientBehavior"。

 

  1. < behaviors>   
  2. < endpointBehaviors>   
  3. < behavior name="myClientBehavior">   
  4. < clientCredentials>   
  5. < serviceCertificate>   
  6. < authentication certificateValidationMode=
    "Custom" customCertificateValidatorType=
    "ClientWeb.CustomX509Validator.
    MyX509Validator,ClientWeb"
     />   
  7. < /serviceCertificate>   
  8. < /clientCredentials>   
  9. < /behavior>   
  10. < /endpointBehaviors>   
  11. < /behaviors>  

 

 

OK,客户端代码和配置完成,现在你可以运行自己的WCF用户密码认证程序了。

责任编辑:曹凯 来源: 博客园
相关推荐

2010-02-23 10:25:29

2010-03-01 10:45:59

WCF集合类

2010-02-25 17:22:39

WCF服务行为

2010-03-02 16:43:46

2017-06-07 10:55:17

VMwareNSX应用

2010-03-01 13:06:49

WCF继承

2010-02-22 14:53:17

WCF用户密码

2010-03-02 17:35:20

WCF服务加载

2010-02-26 10:56:06

WCF Stream

2009-12-21 14:49:27

2010-02-24 14:05:08

WCF openati

2010-02-22 13:28:05

WCF异步调用

2021-08-28 10:06:29

VueJavascript应用

2009-11-03 11:03:00

CDN接入技术

2024-02-27 16:27:42

物联网IOT智能连接

2010-01-06 15:21:00

软交换技术

2010-11-25 10:05:22

Visual StudSilverlightWCF

2010-03-01 17:52:03

WCF选择绑定

2010-02-26 14:19:03

WCF用户验证

2009-11-09 11:21:32

路由策略
点赞
收藏

51CTO技术栈公众号