在这一部分,我们将主要介绍当向一个组织或者其他安全环境部署和使用服务的问题以及遇到的情况。由于服务可能被宰一个Windows网络的另外机器调用,我们可以利用非基于因特网部署原有的共享认证和授权系统的优势。
因为我们在一个本地网络中,我们可以利用绑定类型的优势,比如TCP(NetTcpBinding),命名管道(如果在同一台机器)来改进性能和效率。我们也可以采用可信赖架构比如MSMQ(NetTcpBinding).
章节示例介绍
这一章用模型来显示的例子有基于WCF的服务和调用者,它们在一个企业防火墙后的局域网间通信。我们按照基本模型来搭建拓扑,有一个契约/实现类库,控制台宿主应用(SampleHost),和客户端控制台应用(ClientConsole).拓扑结构在图片8.2显示,客户端,宿主和其他资源比如数据库都在一个企业防火墙后面并被从开发互联网中分离开。
服务实现是SampleService,它有一个ISamples.cs定义了三个简单操作,GetSecretCode,GetMemberCode和GetPublicCode 在列表8.17中显示。
列表8.17 ISamples.cs 服务契约接口
namespace SampleService { [ServiceContract] public interface ISamples { [OperationContract] string GetSecretCode(); [OperationContract] string GetMemberCode(); [OperationContract] string GetPublicCode(); } }
ISamples 接口由列表8.18现实的Samples.cs类实现。
列表8.18 Samples.cs 服务实现类
namespace SampleService { public class Samples : ISamples { #region ISamples 成员 public string GetSecretCode() { DisplaySecurityDetails(); return "The Secret Code"; } public string GetMemberCode() { DisplaySecurityDetails(); return "The Member-Only Code"; } public string GetPublicCode() { DisplaySecurityDetails(); return "The Public Code"; } #endregion private static void DisplaySecurityDetails() { Console.WriteLine("Windows Identity = " + WindowsIdentity.GetCurrent().Name); Console.WriteLine("Thread CurrentPrincipal Identity = " + Thread.CurrentPrincipal.Identity.Name); Console.WriteLine("ServiceSecurityContext Primary Identity = " + ServiceSecurityContext.Current.PrimaryIdentity.Name); Console.WriteLine("ServiceSecurityContext Windows Identity = " + ServiceSecurityContext.Current.WindowsIdentity.Name); } } }
我们已经在Windows中创建了两个将在下一些例子中使用的本地测试账户。使用计算机管理控制台并打开本地用户和组节点。在用户节点下,创建两个账户。在我们的例子中,我们创建了Peter Admin(用户名"peter")和Jessica Member(用户名"jessica").
使用Windows证书认证用户
让我们由查看一个使用Windows证书认证的基于TCP服务的默认行为。服务使用NetTcpBinding配置,像在列表8.19中显示的那样。注意我们已经为了生存代理使能元数据暴露功能。
列表8.19 使用默认安全配置的TCP服务配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="ServiceBehavior" name="SampleService.Samples"> <endpoint address="" binding="netTcpBinding" bindingConfiguration="" name="netTcp" contract="SampleService.ISamples" /> <endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="" name="mex" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:8080/Samples" /> <add baseAddress="net.tcp://localhost:8090/Samples" /> </baseAddresses> </host> </service> </services> </system.serviceModel> </configuration>
ClientConsole应用程序简单地创建一个生的代理类的实例并顺序对每个操作进行调用,在列表8.20中显示。
列表8.20 ClienConsole应用程序通过TCP调用SamplesService
namespace Client { class Program { static void Main(string[] args) { Console.WriteLine("Press ENTER to make service call."); Console.ReadLine(); Samples.SamplesClient proxy = new Client.Samples.SamplesClient("netTcp"); try { Console.WriteLine(proxy.GetPublicCode()); Console.WriteLine(proxy.GetMemberCode()); Console.WriteLine(proxy.GetSecretCode()); } catch (Exception ex) { Console.WriteLine("exception = " + ex.Message); } Console.ReadLine(); } } }
当ClientConsole和SampleHost一起运行时,每次调用都成功完成且SampleHost把身份细节写到它的控制台(通过DisplaySecurityDetails方法)。所有身份都报告为运行ClientConsole应用程序的Windows用户。这是期待的结果因为我们还没有介绍任何其他身份。