您的位置:首页 > 其它

艾伟_转载:WCF安全之EndPointIdentity

2011-08-29 00:22 218 查看
   最近在做一个项目,应用了WCF进行分布式开发,中间还涉及到消息路由器等,好在有WCF提供了强大的基础支持,当然,本身也作了不少的扩展,实际,我 最关心的是WCF的安全问题,网上不少朋友介绍的WCF的安全也是少得可怜,微软发布的WCF Security GUID好像讲得也只是入门级别的教程,离真正应用到项目中还是有很大的距离,这也让我萌发了分享的想法,今天先放出来占个位置吧,有反对的朋友砖头轻 点,呵~,可以告诉你,WCF的安全里,有很多的小秘密,当然还是要告诉你,并且有此小秘密是要自己去体验后才知道,在博客排版方面,李会军(军哥)让人 感觉最舒服,在解说方面,军哥也是以简洁著称,我在这里也学习一下,一起简洁吧,我希望以后的WCF安全探讨里,一次只讲一个小内容好了~

  概述

   Windows Communication Foundation (WCF) 是 Microsoft 为构建面向服务的应用程序而提供的统一编程模型(摘自MSDN),在分布式环境下的安全问题尤为重要,如果你觉得使用了WCF默认的安全措施可以让你高枕 无忧,那明天你可就以回家种田了,当然,对于学习来说,足够了~,但我们讲的是真正的项目应用,WCF在各种协议下的安全提供和保证是不尽相同的。

  背景

故事发生在一个阳光明媚的下午,一名女子为了混入某小区行窃,将上次偷到的管道维修工作牌别在胸前,当她走近管理员身边时,被管理员一把抓个正着,原来这小区从上次失窃事件后,已经将维修队解散,现在维修都是由管理员联系外部人员,自然也不用别什么工作牌了。

  问题呈现

  1、许多朋友对这个EndPointIdentity相当的不屑顾,千万不要小看它呀,有时候你被wcf弄生弄死的时候还不知道为什么,这次你应该看清楚了。当你新建一个WCF服务类库时,正确的EndPointIdentity声明如下

//客户端配置
<binding name="EndpointBinding">
<security mode="Message">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
<message clientCredentialType="Certificate"/>
security>
binding>
netTcpBinding>
bindings>
<client>
<endpoint address ="net.tcp://localhost:8799/UserService/UserData"
binding="netTcpBinding"
contract="Client.References.IUserData"
bindingConfiguration="EndpointBinding"
behaviorConfiguration="UserDataBehavior">
<identity>
<dns value="localhost"/>
identity>
endpoint>
client>

//服务器配置
<binding name="EndpointBinding">
<security mode="Message">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
<message clientCredentialType="Certificate"/>
security>
binding>
netTcpBinding>
bindings>
<services>
<service name="UserService.UserData" behaviorConfiguration="UserDataBehavior">
<host>
<baseAddresses>
<add baseAddress = "net.tcp://localhost:8799/UserService" />
baseAddresses>
host>
<endpoint address ="UserData"
binding="netTcpBinding"
contract="UserService.IUserData"
bindingConfiguration="EndpointBinding">
endpoint>
service>

看看配置文件,你发现了什么?是的,服务器端的标识被删除,客户端的标识还是dns并且值为localhost,调用服务抛出异常:

==========================

传出消息标识检查失败。所预期的远程终结点的 DNS 标识为“localhost”,但是远程终结点提供的 DNS 请求为“192168168151service”。如果此远程终结点合法,您可以通过在创建通道代理时明确地将 DNS 标识“192168168151service”指定为 EndpointAddress 的“标识”属性来解决此问题。

==========================

在这里,我们忽略了一个事实,当你在服务中将安全策略调整了消息级别安全时,服务必须配置x509证书,正所谓你叫天不应,叫地不灵啊,这时候EndpointIdentity跑出来搞乱了,明明服务器默认是dns标识,值为:loclahost。为什么突然跑出来个“192168168151service”呀?我也很想知道,原来,在服务配置证书后,默认的dns将被替换为证书主题,只要你把dns配置改回来,一切又没问题了。

  [b]新问题[/b]

这时候突然冒出来一个新的问题,如果有多个服务器的时候怎么办呀?多个服务器,多半会伴随着路由器的出现(这只是一种假设,与业务有关),我也很想知道,有多个的时候的情况。

  解决它

答案是通过代码动态创建一个EndpointIdentity,代码比较简单,如下:

UserDataClient client = new UserDataClient();
EndpointIdentity identity = EndpointIdentity.CreateDnsIdentity("192168168151service");
AddressHeaderCollection headers = client.Endpoint.Address.Headers;//如果需要,还可以在这里加入自定义的头消息
Uri uri = client.Endpoint.Address.Uri;
EndpointAddress remoteaddress = new EndpointAddress(uri, identity, headers.ToArray());
UserDataClient newClient = new UserDataClient(client.Endpoint.Binding, remoteaddress);
newClient.ClientCredentials.ClientCertificate.Certificate = client.ClientCredentials.ClientCertificate.Certificate;
client.Abort();//关闭旧通道,当然,这里你还可以用通道工厂创建对象,实际上也很简单
string msg = newClient.GetData(50);

===========================================================

后话

1、实际上,以上的这段代码这里还包括动态的创建地址头的相关信息,声明一个client的好处是可以使用原有的地址头信息(uri,binding等)

2、下篇更精彩,欢迎转载,但请注明出处--梁规晓博客(http://www.cnblogs.com/viter/)!

说得不对的地方,欢迎拍砖!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: