概述
Windows Communication Foundation (WCF) 是 Microsoft 为构建面向服务的应用程序而提供的统一编程模型(摘自MSDN),在分布式环境下的安全问题尤为重要,如果你觉得使用了WCF默认的安全措施可以让你高枕 无忧,那明天你可就以回家种田了,当然,对于学习来说,足够了~,但我们讲的是真正的项目应用,WCF在各种协议下的安全提供和保证是不尽相同的。
背景
在上一篇X509证书介绍后,相信大家对怎么使用X509证书在WCF的安全策略中有一定的了解,本章主要讲述在WCF的消息安全模式下的服务器对客户端基于自定义用户名和密码的身份验证模式。当所有内置 UserNamePassword 验证模式均不符合应用程序的要求时,你可以能过继承 System.IdentityModel.Selectors.UserNamePasswordValidator 抽象类,并重写其Validate方法来实现自己的用户名密码验证程序,实际上,内置的用户名密码验证方式比自定义的用户名密码验证方式要可靠得多,因为自定义的用户名密码验证程序任何人都可以构造,但是标准的用户名密码验证方式刚是将用户提供的用户名密码映射到windows账户,所以,如果映射失败,意味着验证不通过,以下示例在服务器端启用自定义的用户名密码验证程序,客户端在调用服务前需要提供访问服务所需要的用户名密码,并在EndpointIdenty中向服务器标识自己是合法用户,具体标识参见本系列第二章:WCF安全之EndPointIdentity。如果服务器验证通过,将向客户端返回一个从数据库查询到的xml列(xElement对象),并将内容打印到控制台。
开始吧
1、实现自定义用户名密码方式有哪些要求?
如上面的所讲,首先,我们需要建立一个类,来继承自System.IdentityModel.Selectors.UserNamePasswordValidator抽象类,并重其validate方法,代码比较简单,当然,这只是用于演示作用,如果是在实际的项目中,你完全可以将用户名密码存储在持久化介质上,请看实现:
{
public override void Validate(string userName, string password)
{
if (userName != "admin" || password != "admin")
{
throw new SecurityNegotiationException("验证用户名和密码时,未通过检测");
}
}
}
2、配置安全策略和模式
你可以在代码或者在配置文件中完成此安全策略实现过程,但是如果你是以代码方式实现,做之前请参考Artech的文章:[原创]WCF技术剖析之八:ClientBase中对ChannelFactory的缓存机制
(请原谅我引用),配置文件实现如下:
<binding name="EndpointBinding">
<security mode="Message">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
//服务配置
<serviceCredentials>
<serviceCertificate findValue="192168168151service"
x509FindType="FindBySubjectName"
storeLocation="LocalMachine"
storeName="My"/>
<userNameAuthentication customUserNamePasswordValidatorType="UserDataServcie.CustomUserPassword,UserDataServcie" userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
在上面的过程中,我们的绑定配置中的安全策略必须是消息级别的安全,因为在传输级别中,是不提供用户名密码验证方式的。两种级别的的选择比较主要体现在安全和效率上,如果你的传输效率上没有什么问题,建议你选择第四种安全策略:TransportWithMessageCredential,TransportWithMessageCredential的好处是既提供安全传输,又保证消息加密,多好!相对来说还是比较简单的吧
3、证书的配置
启用消息安全策略必须配置x509证书,如果你不配置,服务启动将会收到一个异常:未提供安全证书。从上一章后,你也会觉得证书的配置都是比较简单的吧。所以这里也不用过多的费话了。
4、客户端调用服务
客户端在调用服务前设置一个用户名密码(此用户名密码你可动态配置,具体怎么动态你随意,可以是从持久介质上提取,也可以是用户输入),如下:
client.ClientCredentials.UserName.UserName = "admin";
client.ClientCredentials.UserName.Password = "admin";
UserExtension usereE = client.GetUserExtension();
XElement xe = client.GetUserExtensionXElement(null);
Console.WriteLine("调用成功,开始打印消息.");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("==================================");
Console.WriteLine(xe.Value);
5、调用成功,控制台输出调用信息
=============================================
后话:总体来说,自定义的用户名密码验证程序还是比较简单的,只是在效率上会有点问题。
欢迎转载,但请注明出处--lsotcode博客(http://www.cnblogs.com/viter/)!
说得不对的地方,欢迎拍砖!