保护服务的基于 WCF 的通信Secure WCF-based communications for a service

安全是通信最为重视的要素之一。Security is one of the most important aspects of communication. Reliable Services 应用程序框架提供了一些预先生成的通信堆栈和工具供你用来提高安全性。The Reliable Services application framework provides a few prebuilt communication stacks and tools that you can use to improve security. 本文介绍如何在使用服务远程处理时提高安全性。This article talks about how to improve security when you're using service remoting.

我们将使用一个现有示例来解释如何为 Reliable Services 设置基于 WCF 的通信堆栈。We are using an existing example that explains how to set up a WCF-based communication stack for reliable services. 若要在使用基于 WCF 的通信堆栈时帮助保护服务,请遵循以下步骤:To help secure a service when you're using a WCF-based communication stack, follow these steps:

  1. 对于服务,需要帮助保护创建的 WCF 通信侦听器 (WcfCommunicationListener)。For the service, you need to help secure the WCF communication listener (WcfCommunicationListener) that you create. 为此,请修改 CreateServiceReplicaListeners 方法。To do this, modify the CreateServiceReplicaListeners method.

    protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
    {
        return new[]
        {
            new ServiceReplicaListener(
                this.CreateWcfCommunicationListener)
        };
    }
    
    private WcfCommunicationListener<ICalculator> CreateWcfCommunicationListener(StatefulServiceContext context)
    {
       var wcfCommunicationListener = new WcfCommunicationListener<ICalculator>(
            serviceContext:context,
            wcfServiceObject:this,
            // For this example, we will be using NetTcpBinding.
            listenerBinding: GetNetTcpBinding(),
            endpointResourceName:"WcfServiceEndpoint");
    
        // Add certificate details in the ServiceHost credentials.
        wcfCommunicationListener.ServiceHost.Credentials.ServiceCertificate.SetCertificate(
            StoreLocation.LocalMachine,
            StoreName.My,
            X509FindType.FindByThumbprint,
            "9DC906B169DC4FAFFD1697AC781E806790749D2F");
        return wcfCommunicationListener;
    }
    
    private static NetTcpBinding GetNetTcpBinding()
    {
        NetTcpBinding b = new NetTcpBinding(SecurityMode.TransportWithMessageCredential);
        b.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
        return b;
    }
    
  2. 在客户端中,在前面示例中创建的 WcfCommunicationClient 类保持不变。In the client, the WcfCommunicationClient class that was created in the previous example remains unchanged. 但是,需要重写 WcfCommunicationClientFactoryCreateClientAsync 方法:But you need to override the CreateClientAsync method of WcfCommunicationClientFactory:

    public class SecureWcfCommunicationClientFactory<TServiceContract> : WcfCommunicationClientFactory<TServiceContract> where TServiceContract : class
    {
        private readonly Binding clientBinding;
        private readonly object callbackObject;
        public SecureWcfCommunicationClientFactory(
            Binding clientBinding,
            IEnumerable<IExceptionHandler> exceptionHandlers = null,
            IServicePartitionResolver servicePartitionResolver = null,
            string traceId = null,
            object callback = null)
            : base(clientBinding, exceptionHandlers, servicePartitionResolver,traceId,callback)
        {
            this.clientBinding = clientBinding;
            this.callbackObject = callback;
        }
    
        protected override Task<WcfCommunicationClient<TServiceContract>> CreateClientAsync(string endpoint, CancellationToken cancellationToken)
        {
            var endpointAddress = new EndpointAddress(new Uri(endpoint));
            ChannelFactory<TServiceContract> channelFactory;
            if (this.callbackObject != null)
            {
                channelFactory = new DuplexChannelFactory<TServiceContract>(
                this.callbackObject,
                this.clientBinding,
                endpointAddress);
            }
            else
            {
                channelFactory = new ChannelFactory<TServiceContract>(this.clientBinding, endpointAddress);
            }
            // Add certificate details to the ChannelFactory credentials.
            // These credentials will be used by the clients created by
            // SecureWcfCommunicationClientFactory.  
            channelFactory.Credentials.ClientCertificate.SetCertificate(
                StoreLocation.LocalMachine,
                StoreName.My,
                X509FindType.FindByThumbprint,
                "9DC906B169DC4FAFFD1697AC781E806790749D2F");
            var channel = channelFactory.CreateChannel();
            var clientChannel = ((IClientChannel)channel);
            clientChannel.OperationTimeout = this.clientBinding.ReceiveTimeout;
            return Task.FromResult(this.CreateWcfCommunicationClient(channel));
        }
    }
    

    使用 SecureWcfCommunicationClientFactory 创建 WCF 通信客户端 (WcfCommunicationClient)。Use SecureWcfCommunicationClientFactory to create a WCF communication client (WcfCommunicationClient). 使用客户端调用服务方法。Use the client to invoke service methods.

    IServicePartitionResolver partitionResolver = ServicePartitionResolver.GetDefault();
    
    var wcfClientFactory = new SecureWcfCommunicationClientFactory<ICalculator>(clientBinding: GetNetTcpBinding(), servicePartitionResolver: partitionResolver);
    
    var calculatorServiceCommunicationClient =  new WcfCommunicationClient(
        wcfClientFactory,
        ServiceUri,
        ServicePartitionKey.Singleton);
    
    var result = calculatorServiceCommunicationClient.InvokeWithRetryAsync(
        client => client.Channel.Add(2, 3)).Result;
    

有关后续步骤,请阅读 Reliable Services 中使用 OWIN 的 Web APIAs a next step, read Web API with OWIN in Reliable Services.