第八篇:WCF安全
WCF提供了非常丰富的加密机制与审核机制,以保证对外提供的服务安全可靠。本文是简单教程,所以只挑其中的一小部分来聊聊。
先来看看最简单的Windows认证。
所谓Windows认证,是指客户端访问时,要提供服务端认可的Windows用户身份。
1、服务端
安全配置主要体现在App.config中:
- <?xmlversion="1.0"encoding="utf-8"?> 
- <configuration> 
- <system.serviceModel> 
- <services> 
- <servicename="Server.DataProvider"> 
- <!-- 本例中使用netTcpBinding,注意指定了一个名为tcpBinding的设置,见下文 --> 
- <endpointaddress=""binding="netTcpBinding"contract="Server.IData"bindingConfiguration="tcpBinding"/> 
- <host> 
- <baseAddresses> 
- <addbaseAddress="net.tcp://localhost:8081/wcf"/> 
- </baseAddresses> 
- </host> 
- </service> 
- </services> 
- <!--客户端的身份认证是设置在bindings节中的--> 
- <bindings> 
- <!--注意此节要与前面的binding匹配,表示为netTcpBinding方式的绑定进行配置--> 
- <netTcpBinding> 
- <!--定义一个名为tcpBinding的设置,就是前面endpoint中用到的--> 
- <bindingname="tcpBinding"> 
- <!--使用Message方式的加密,至于它与Transport方式的区别,可先忽略,后面再讲--> 
- <securitymode="Message"> 
- <!--指定客户端认证使用Windows方式--> 
- <messageclientCredentialType="Windows"/> 
- </security> 
- </binding> 
- </netTcpBinding> 
- </bindings> 
- </system.serviceModel> 
- </configuration> 
契约实现类我们修改一下,方便看到调用者的身份:
- using System; 
- using System.ServiceModel; 
- namespace Server 
- { 
- [ServiceBehavior] 
- publicclass DataProvider : IData 
- { 
- publicstring SayHello() 
- { 
- //WindowsIdentity即代表访问者的身份标识 
- returnstring.Format("Hello {0}", OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name); 
- } 
- } 
- } 
2、客户端
客户端要对应调整App.config:
- <?xmlversion="1.0"encoding="utf-8"?> 
- <configuration> 
- <system.serviceModel> 
- <client> 
- <!--定义endpoint时指定使用特定的配置,另外这个IP是一会儿运行服务端的机器的IP--> 
- <endpointbinding="netTcpBinding"contract="Server.IData"address="net.tcp://192.168.90.90:8081/wcf"name="DataProvider"bindingConfiguration="tcp"/> 
- </client> 
- <!--客户端与服务端的bindings节设置一致--> 
- <bindings> 
- <netTcpBinding> 
- <bindingname="tcp"> 
- <securitymode="Message"> 
- <messageclientCredentialType="Windows"/> 
- </security> 
- </binding> 
- </netTcpBinding> 
- </bindings> 
- </system.serviceModel> 
- </configuration> 
然后是代码,要指定访问时客户端使用的用户名密码:
- using System; 
- using System.ServiceModel; 
- using System.ServiceModel.Channels; 
- namespace Client 
- { 
- class Program 
- { 
- staticvoid Main(string[] args) 
- { 
- //创建一个ChannelFactory,指定使用名为DataProvider的配置 
- var factory = new ChannelFactory<Server.IData>("DataProvider"); 
- //指定用户名、密码,这个Test是服务端Windows上的一个普通帐户,如果加入了域,还要指定ClientCredential.Domain 
- factory.Credentials.Windows.ClientCredential.UserName= "Test"; 
- factory.Credentials.Windows.ClientCredential.Password = "test"; 
- //创建Channel,并调用SayHello方法 
- var proxy = factory.CreateChannel(); 
- Console.WriteLine(proxy.SayHello()); 
- ((IChannel)proxy).Close(); 
- } 
- } 
- } 
其中的指定的用户名与密码是服务端存在的一个Windows用户。
OK,在两台机器上分别运行服务端和客户端,能够正常完成调用,输出“Hello Test-PC\Test”,这个Test-PC\Test就是我们调用时传递的用户身份,注意是“机器名\用户名”的形式,如果是AD环境,那么就是“域\用户名”的形式。
如果给定一个错误的用户名密码,则调用时会收到Exception:
- 未处理的异常: System.ServiceModel.Security.SecurityNegotiationException: 调用方未由服务进行身份验证。 ---> System.ServiceModel.FaultException: 无法满足对安全令牌的请求,因为身份验证失败。 
- 在 System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target) 
- 在 System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState) 
是一个身份验证失败的异常。
用Windows帐户来做验证,其实是个挺麻烦的事情,只有较少的系统是这么做的,我们还是希望能用更通用的用户名密码来进行身份验证,下一篇我们就来看看如何做。
本文出自 “兔子窝” 博客,请务必保留此出处http://boytnt.blog.51cto.com/966121/815117
转载于:https://blog.51cto.com/rmlifejun/1264407