以前我们用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项目上添加引用'System.IdentityModel'然后我们建立一个新的类文件并继承自'System.IdentityModel.Selectors.UserNamePasswordValidator',然后我们重写里面的'Validate'方法来实现用户名密码认证逻辑。代码如下;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
namespace ServerWcfService.CustomValidators
{
public class MyCustomValidator : UserNamePasswordValidator
{
/// <summary>
/// Validates the user name and password combination.
/// </summary>
/// <param name="userName">The user name.</param>
/// <param name="password">The password.</param>
public override void Validate(string userName, string password)
{
// validate arguments
if (string.IsNullOrEmpty(userName))
throw new ArgumentNullException("userName");
if (string.IsNullOrEmpty(password))
throw new ArgumentNullException("password");
// check if the user is not xiaozhuang
if (userName != "xiaozhuang" || password != "123456")
throw new SecurityTokenException("用户名或者密码错误!");
}
}
}