本主题介绍用于创建安全 Windows Communication Foundation (WCF) 应用程序的基本编程任务。 本主题仅介绍身份验证、机密性和完整性,统称为 传输安全性。 本主题不包括授权(对资源或服务的访问控制):有关授权的信息,请参阅 授权。
注释
有关安全概念的宝贵介绍,尤其是在 WCF 方面,请参阅 MSDN 上的 "Web 服务增强功能 (WSE) 3.0 的方案、模式和实现指导" 一组模式和实践教程。
编程 WCF 安全性基于以下三个步骤设置:安全模式、客户端凭据类型和凭据值。 可以通过代码或配置执行这些步骤。
设置安全模式
下面介绍了在 WCF 中使用安全模式进行编程的一般步骤:
选择符合应用程序要求的预定义绑定之一。 有关绑定选项的列表,请参阅 System-Provided 绑定。 默认情况下,几乎每个绑定都已启用安全性。 一个例外是 BasicHttpBinding 类(使用配置时,为 <basicHttpBinding>)。
您选择的绑定决定传输方式。 例如, WSHttpBinding 使用 HTTP 作为传输; NetTcpBinding 使用 TCP。
选择绑定的安全模式之一。 请注意,你选择的绑定决定了可用的模式选项。 例如, WSDualHttpBinding 不允许传输安全性(不是选项)。 同样,MsmqIntegrationBinding和NetNamedPipeBinding都不允许消息安全性。
你有三个选择:
Transport
传输安全性取决于所选绑定使用的机制。 例如,如果使用
WSHttpBinding
,则安全机制是安全套接字层(SSL)(也是 HTTPS 协议的机制)。 一般来说,传输安全性的主要优势是,无论使用哪种传输,它都可提供良好的吞吐量。 但是,它确实有两个限制:第一个是传输机制规定用于对用户进行身份验证的凭据类型。 仅当服务需要与其他需要不同类型的凭据的服务进行互作时,这是一个缺点。 第二个限制是,因为安全不是在消息级应用的,所以安全是逐个跃点实现的,而不是以端对端方式实现的。 仅当客户端和服务之间的消息路径包括中介时,此后一个限制是一个问题。 有关要使用的传输的详细信息,请参阅 “选择传输”。 有关使用传输安全性的详细信息,请参阅 传输安全概述。Message
消息安全性意味着每个消息都包含必要的标头和数据,以确保消息安全。 由于标头的组合各不相同,因此可以包含任意数量的凭据。 如果与其他需要传输机制无法提供的特定凭据类型的服务进行互作,或者消息必须与多个服务一起使用,其中每个服务都需要不同的凭据类型,则这将成为一个因素。
有关详细信息,请参阅 消息安全性。
TransportWithMessageCredential
此选项使用传输层来保护消息传输,而每个消息都包含其他服务所需的丰富凭据。 这结合了传输安全性的性能优势和消息安全性的丰富凭据优势。 这具有以下绑定: BasicHttpBinding、 WSFederationHttpBinding、 NetPeerTcpBinding和 WSHttpBinding。
如果决定对 HTTP 使用传输安全性(换句话说为 HTTPS),则还必须使用 SSL 证书配置主机并在端口上启用 SSL。 有关详细信息,请参阅 HTTP 传输安全性。
如果使用 WSHttpBinding 且不需要建立安全会话,请将 EstablishSecurityContext 属性设置为
false
。当客户端和服务使用对称密钥创建通道时,将发生安全会话(客户端和服务器对会话长度使用相同的密钥,直到对话关闭)。
设置客户端凭据类型
根据需要选择客户端凭据类型。 有关详细信息,请参阅 “选择凭据类型”。 以下客户端凭据类型可用:
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
根据您如何设置模式,必须设置凭据类型。 例如,如果选择了wsHttpBinding
该模式,并且已将模式设置为“Message”,则还可以将 clientCredentialType
Message 元素的属性设置为以下值之一:None
、、Windows
、UserName
Certificate
、和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()