WCF 安全性程式設計
本主題說明用來建立安全的 Windows Communication Foundation (WCF) 應用程式的基本程式設計工作。 本主題僅涵蓋驗證、機密性與完整性 (統稱為「傳輸安全性」(Transfer Security))。 本主題並未涵蓋授權 (對資源或服務的存取控制);如需授權的詳細資訊,請參閱授權。
注意: |
---|
如需安全性概念的重要簡介 (特別是關於 WCF),請參閱 MSDN 上的 Web Services Enhancements (WSE) 3.0 的案例、模式和實作指引 (英文) 中的模式組與做法教學課程。 |
WCF 安全性的程式設計是以設定下列項目的三個步驟為基礎:安全性模式、用戶端認證類型,以及認證值。 您可以透過程式碼或組態執行這些步驟。
設定安全性模式
下列說明在 WCF 中使用安全性模式來進行設計程式的一般步驟:
針對應用程式需求選取一項適合的預先定義繫結。 如需繫結選擇清單,請參閱系統提供的繫結。 根據預設,幾乎所有的繫結都會啟用安全性。 唯一的例外就是 BasicHttpBinding 類別 (使用組態時,為 basicHttpBinding Element)。
您選取的繫結將決定傳輸方式。 例如,WSHttpBinding 會使用 HTTP 做為傳輸方式;而 NetTcpBinding 則使用 TCP。
選取其中一項安全性模式來進行繫結。 請注意,您選取的繫結會決定可用的模式選項有哪些。 例如,WSDualHttpBinding 不允許使用傳輸安全性 (未包含在選項中)。 同樣地,MsmqIntegrationBinding 和 NetNamedPipeBinding 也都不允許使用訊息安全性。
您有下列三個選擇:
Transport
傳輸安全性將視您選取之繫結所使用的機制而定。 例如,假使您使用 WSHttpBinding,則安全性機制為安全通訊端層 (SSL) (同時也是 HTTPS 通訊協定的機制)。 一般來說,傳輸安全性的主要優點在於,不管您使用哪種傳輸機制,都能提供良好的輸送量。 但是,它有兩項限制:首先就是傳輸機制會指出用來驗證使用者的認證類型。 只有當服務需要與其他要求不同認證類型的服務交互操作時,這個限制才會成為缺點。 第二個限制是,由於訊息層級並未套用安全性,所以會以躍點方式 (而不是以端對端方式) 來實作安全性。 只有當用戶端與服務之間的訊息路徑包含媒介時,第二個限制才會成為問題。如需詳細資訊 該使用哪個傳輸機制的詳細資訊,請參閱選擇傳輸。如需詳細資訊 使用傳輸安全性,請參閱傳輸安全性概觀
Message
訊息安全性表示每則訊息都包含保護訊息安全的必要標頭與資料。 由於標頭的組成份子各有不同,因此您可以加入任何數量的認證。 如果您正與其他需要特定認證類型 (但無法適用傳輸機制) 的服務進行交互操作,或是如果訊息必須與一個以上的服務搭配使用,而其中每個服務需要不同的認證類型時,這項特性就會變成一個要件。
如需詳細資訊,請參閱 WCF 中的訊息安全性.
TransportWithMessageCredential
這項選擇使用傳輸層來保護訊息傳輸的安全,而每則訊息則包含其他服務所需的豐富認證。 這項選擇會將傳輸安全性的效能優點,與訊息安全性的豐富認證優勢加以結合。 您可透過下列繫結來獲得這項優勢:BasicHttpBinding、WSFederationHttpBinding、NetPeerTcpBinding 和 WSHttpBinding。
如果您決定在 HTTP 上使用傳輸安全性 (亦即,HTTPS),必須同時使用 SSL 憑證來設定主機,並啟用連接埠上的 SSL。 如需詳細資訊,請參閱 HTTP 傳輸安全性.
如果您正在使用 WSHttpBinding 而且不需要建立安全工作階段,請將 EstablishSecurityContext 屬性設為 false。
當用戶端與服務透過對稱金鑰來建立通道時,就會產生安全工作階段 (用戶端與伺服器都會在對話期間全程使用相同的金鑰,直到對話結束為止)。
設定用戶端認證類型
視需要選取用戶端認證類型。 如需詳細資訊,請參閱 選取認證類型. 下列為可用的用戶端認證類型:
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
視模式的設定方式而定,您必須設定認證類型。 例如,如果您選取了 wsHttpBinding,並將模式設為 [訊息],則也可以將 Message 項目的 clientCredentialType 屬性設為下列其中一個值:None、Windows、UserName、Certificate 和 IssuedToken,如下列組態範例所示。
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="myBinding">
<security mode="Message"/>
<message clientCredentialType="Windows"/>
</binding>
</bindings>
</system.serviceModel>
或在程式碼中:
Dim b As New WSHttpBinding()
b.Name = "myBinding"
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
WSHttpBinding b = new WSHttpBinding();
b.Name = "myBinding";
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType=MessageCredentialType.Windows;
設定服務認證值
一旦您選取了用戶端認證類型,就必須設定實際認證以供服務與用戶端使用。 在服務上,認證需透過 ServiceCredentials 類別來加以設定,並由 ServiceHostBase 類別的 Credentials 屬性傳回。 使用中的繫結意指服務認證類型、選擇的安全性模式,以及用戶端認證類型。 下列程式碼將為服務認證設定憑證。
' 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 commmunication error occurred: {0}", ce.Message)
Console.WriteLine()
Catch exc As System.Exception
Console.WriteLine("An unforseen error occurred: {0}", exc.Message)
Console.ReadLine()
End Try
// 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 commmunication error occurred: {0}", ce.Message);
Console.WriteLine();
}
catch (System.Exception exc)
{
Console.WriteLine("An unforseen error occurred: {0}", exc.Message);
Console.ReadLine();
}
設定用戶端認證值
在用戶端上,用戶端認證值是使用 ClientCredentials 類別進行設定,並由 ClientBase 類別的 ClientCredentials 屬性傳回。 下列程式碼將透過 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.
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()
// 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 @ {0}", address);
Console.WriteLine("Press enter to close the service");
Console.ReadLine();