对 WCF 安全性进行编程

本主题介绍用于创建安全 Windows Communication Foundation (WCF) 应用程序的基本编程任务。 本主题仅介绍身份验证、机密性和完整性,统称为 传输安全性。 本主题不包括授权(对资源或服务的访问控制):有关授权的信息,请参阅 授权

注释

有关安全概念的宝贵介绍,尤其是在 WCF 方面,请参阅 MSDN 上的 "Web 服务增强功能 (WSE) 3.0 的方案、模式和实现指导" 一组模式和实践教程。

编程 WCF 安全性基于以下三个步骤设置:安全模式、客户端凭据类型和凭据值。 可以通过代码或配置执行这些步骤。

设置安全模式

下面介绍了在 WCF 中使用安全模式进行编程的一般步骤:

  1. 选择符合应用程序要求的预定义绑定之一。 有关绑定选项的列表,请参阅 System-Provided 绑定。 默认情况下,几乎每个绑定都已启用安全性。 一个例外是 BasicHttpBinding 类(使用配置时,为 <basicHttpBinding>)。

    您选择的绑定决定传输方式。 例如, WSHttpBinding 使用 HTTP 作为传输; NetTcpBinding 使用 TCP。

  2. 选择绑定的安全模式之一。 请注意,你选择的绑定决定了可用的模式选项。 例如, WSDualHttpBinding 不允许传输安全性(不是选项)。 同样,MsmqIntegrationBindingNetNamedPipeBinding都不允许消息安全性。

    你有三个选择:

    1. Transport

      传输安全性取决于所选绑定使用的机制。 例如,如果使用 WSHttpBinding ,则安全机制是安全套接字层(SSL)(也是 HTTPS 协议的机制)。 一般来说,传输安全性的主要优势是,无论使用哪种传输,它都可提供良好的吞吐量。 但是,它确实有两个限制:第一个是传输机制规定用于对用户进行身份验证的凭据类型。 仅当服务需要与其他需要不同类型的凭据的服务进行互作时,这是一个缺点。 第二个限制是,因为安全不是在消息级应用的,所以安全是逐个跃点实现的,而不是以端对端方式实现的。 仅当客户端和服务之间的消息路径包括中介时,此后一个限制是一个问题。 有关要使用的传输的详细信息,请参阅 “选择传输”。 有关使用传输安全性的详细信息,请参阅 传输安全概述

    2. Message

      消息安全性意味着每个消息都包含必要的标头和数据,以确保消息安全。 由于标头的组合各不相同,因此可以包含任意数量的凭据。 如果与其他需要传输机制无法提供的特定凭据类型的服务进行互作,或者消息必须与多个服务一起使用,其中每个服务都需要不同的凭据类型,则这将成为一个因素。

      有关详细信息,请参阅 消息安全性

    3. TransportWithMessageCredential

      此选项使用传输层来保护消息传输,而每个消息都包含其他服务所需的丰富凭据。 这结合了传输安全性的性能优势和消息安全性的丰富凭据优势。 这具有以下绑定: BasicHttpBindingWSFederationHttpBindingNetPeerTcpBindingWSHttpBinding

  3. 如果决定对 HTTP 使用传输安全性(换句话说为 HTTPS),则还必须使用 SSL 证书配置主机并在端口上启用 SSL。 有关详细信息,请参阅 HTTP 传输安全性

  4. 如果使用 WSHttpBinding 且不需要建立安全会话,请将 EstablishSecurityContext 属性设置为 false

    当客户端和服务使用对称密钥创建通道时,将发生安全会话(客户端和服务器对会话长度使用相同的密钥,直到对话关闭)。

设置客户端凭据类型

根据需要选择客户端凭据类型。 有关详细信息,请参阅 “选择凭据类型”。 以下客户端凭据类型可用:

  • Windows

  • Certificate

  • Digest

  • Basic

  • UserName

  • NTLM

  • IssuedToken

根据您如何设置模式,必须设置凭据类型。 例如,如果选择了wsHttpBinding该模式,并且已将模式设置为“Message”,则还可以将 clientCredentialType Message 元素的属性设置为以下值之一:None、、WindowsUserNameCertificate、和IssuedToken,如以下配置示例所示。

<system.serviceModel>  
<bindings>  
  <wsHttpBinding>  
    <binding name="myBinding">  
      <security mode="Message"/>  
      <message clientCredentialType="Windows"/>  
    </binding>
  </wsHttpBinding>
</bindings>  
</system.serviceModel>  

或者在代码中:

WSHttpBinding b = new WSHttpBinding();
b.Name = "myBinding";
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType=MessageCredentialType.Windows;
Dim b As New WSHttpBinding()
b.Name = "myBinding"
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows

设置服务凭据值

一旦选择了客户端凭据类型,就必须设置可供服务和客户端使用的实际凭据。 在服务上,凭据是使用 ServiceCredentials 类设置的,并由 Credentials 类的属性 ServiceHostBase 返回。 正在使用的绑定意味着服务凭据类型、选择的安全模式和客户端凭据的类型。 下面的代码为服务凭据设置了证书。

// Create the binding for an endpoint.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Message;

// Create the ServiceHost for a calculator.
Uri baseUri = new Uri("net.tcp://MachineName/tcpBase");
Uri[] baseAddresses = new Uri[] { baseUri };
ServiceHost sh = new ServiceHost(typeof(Calculator), baseAddresses);

// Add an endpoint using the binding and a new address.
Type c = typeof(ICalculator);
sh.AddServiceEndpoint(c, b, "MyEndpoint");

// Set a certificate as the credential for the service.
sh.Credentials.ServiceCertificate.SetCertificate(
    StoreLocation.LocalMachine,
    StoreName.My,
    X509FindType.FindBySubjectName,
    "client.com");
try
{
    sh.Open();
    Console.WriteLine("Listening....");
    Console.ReadLine();
    sh.Close();
}
catch (CommunicationException ce)
{
    Console.WriteLine($"A communication error occurred: {ce.Message}");
    Console.WriteLine();
}
catch (System.Exception exc)
{
    Console.WriteLine($"An unforeseen error occurred: {exc.Message}");
    Console.ReadLine();
}
' Create the binding for an endpoint.
Dim b As New NetTcpBinding()
b.Security.Mode = SecurityMode.Message

' Create the ServiceHost for a calculator.
Dim baseUri As New Uri("net.tcp://MachineName/tcpBase")
Dim baseAddresses() As Uri = {baseUri}
Dim sh As New ServiceHost(GetType(Calculator), baseAddresses)

' Add an endpoint using the binding and a new address.
Dim c As Type = GetType(ICalculator)
sh.AddServiceEndpoint(c, b, "MyEndpoint")

' Set a certificate as the credential for the service.
sh.Credentials.ServiceCertificate.SetCertificate( _
                StoreLocation.LocalMachine, _
                StoreName.My, _
                X509FindType.FindBySubjectName, _
                "contoso.com")
Try
    sh.Open()
    Console.WriteLine("Listening....")
    Console.ReadLine()
    sh.Close()
Catch ce As CommunicationException
    Console.WriteLine("A communication error occurred: {0}", ce.Message)
    Console.WriteLine()
Catch exc As System.Exception
    Console.WriteLine("An unforeseen error occurred: {0}", exc.Message)
    Console.ReadLine()
End Try

设置客户端凭据值

在客户端上,使用ClientCredentials类设置客户端凭据值,并通过ClientCredentials类的属性返回ClientBase<TChannel>。 以下代码使用 TCP 协议将证书设置为客户端上的凭据。

// Create a NetTcpBinding and set its security properties. The
// security mode is Message, and the client must be authenticated with
// Windows. Therefore the client must be on the same Windows ___domain.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows;

// Set a Type variable for use when constructing the endpoint.
Type c = typeof(ICalculator);

// Create a base address for the service.
Uri tcpBaseAddress =
    new Uri("net.tcp://machineName.Domain.Contoso.com:8036/serviceName");
// The base address is in an array of URI objects.
Uri[] baseAddresses = new Uri[] { tcpBaseAddress };
// Create the ServiceHost with type and base addresses.
ServiceHost sh = new ServiceHost(typeof(CalculatorClient), baseAddresses);

// Add an endpoint to the service using the service type and binding.
sh.AddServiceEndpoint(c, b, "");
sh.Open();
string address = sh.Description.Endpoints[0].ListenUri.AbsoluteUri;
Console.WriteLine($"Listening @ {address}");
Console.WriteLine("Press enter to close the service");
Console.ReadLine();
' Create a NetTcpBinding and set its security properties. The
' security mode is Message, and the client must be authenticated with
' Windows. Therefore the client must be on the same Windows ___domain.
Dim b As New NetTcpBinding()
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows

' Set a Type variable for use when constructing the endpoint.
Dim c As Type = GetType(ICalculator)

' Create a base address for the service.
Dim tcpBaseAddress As New Uri("net.tcp://machineName.Domain.Contoso.com:8036/serviceName")
' The base address is in an array of URI objects.
Dim baseAddresses() As Uri = {tcpBaseAddress}
' Create the ServiceHost with type and base addresses.
Dim sh As New ServiceHost(GetType(CalculatorClient), baseAddresses)

' Add an endpoint to the service using the service type and binding.
sh.AddServiceEndpoint(c, b, "")
sh.Open()
Dim address As String = sh.Description.Endpoints(0).ListenUri.AbsoluteUri
Console.WriteLine("Listening @ {0}", address)
Console.WriteLine("Press enter to close the service")
Console.ReadLine()

另请参阅