Programování zabezpečení WCF
Toto téma popisuje základní programovací úlohy používané k vytvoření zabezpečené aplikace WCF (Windows Communication Foundation). Toto téma se zabývá pouze ověřováním, důvěrností a integritou, které se souhrnně označuje jako zabezpečení přenosu. Toto téma se nevztahuje na autorizaci (řízení přístupu k prostředkům nebo službám); informace o autorizaci naleznete v tématu Autorizace.
Poznámka:
Cenný úvod do konceptů zabezpečení, zejména pokud jde o WCF, najdete v sadě vzorů a kurzů postupů na webu MSDN ve scénářích, vzorech a pokynech k implementaci pro vylepšení webových služeb (WSE) 3.0.
Programování zabezpečení WCF je založeno na třech krocích nastavení: režim zabezpečení, typ přihlašovacích údajů klienta a hodnoty přihlašovacích údajů. Tyto kroky můžete provést prostřednictvím kódu nebo konfigurace.
Nastavení režimu zabezpečení
Níže jsou vysvětleny obecné kroky pro programování s režimem zabezpečení ve WCF:
Vyberte jednu z předdefinovaných vazeb odpovídajících požadavkům vaší aplikace. Seznam možností vazeb naleznete v tématu Systémové vazby. Ve výchozím nastavení má téměř každá vazba povolené zabezpečení. Jedinou výjimkou je BasicHttpBinding třída (pomocí konfigurace, <basicHttpBinding>).
Vazbu, kterou vyberete, určuje přenos. Například WSHttpBinding jako přenos používá protokol HTTP. NetTcpBinding Používá protokol TCP.
Vyberte jeden z režimů zabezpečení pro vazbu. Všimněte si, že výběr vazby určuje dostupné možnosti režimu. Například WSDualHttpBinding nepovoluje zabezpečení přenosu (není to možnost). Podobně ani MsmqIntegrationBindingNetNamedPipeBinding zabezpečení zpráv neumožňuje.
Máte tři možnosti:
Transport
Zabezpečení přenosu závisí na mechanismu, který používá vámi vybraná vazba. Pokud například používáte
WSHttpBinding
, je bezpečnostní mechanismus ssl (Secure Sockets Layer) (také mechanismus protokolu HTTPS). Obecně řečeno, hlavní výhodou zabezpečení přenosu je, že zajišťuje dobrou propustnost bez ohledu na to, který přenos používáte. Má však dvě omezení: První je, že transportní mechanismus určuje typ přihlašovacích údajů použitý k ověření uživatele. To je nevýhoda pouze v případě, že služba potřebuje spolupracovat s dalšími službami, které vyžadují různé typy přihlašovacích údajů. Druhým je to, že protože zabezpečení není použito na úrovni zpráv, zabezpečení se implementuje způsobem směrování po směrování, nikoli koncovým směrováním. Toto druhé omezení je problém pouze v případě, že cesta zprávy mezi klientem a službou zahrnuje zprostředkovatele. Další informace o tom, kterou dopravu použít, naleznete v tématu Volba přenosu. Další informace o použití zabezpečení přenosu naleznete v tématu Přehled zabezpečení přenosu.Message
Zabezpečení zpráv znamená, že každá zpráva obsahuje potřebná záhlaví a data, aby byla zpráva zabezpečená. Vzhledem k tomu, že složení hlaviček se liší, můžete zahrnout libovolný počet přihlašovacích údajů. To se stane faktorem, pokud spolupracujete s jinými službami, které vyžadují konkrétní typ přihlašovacích údajů, který nemůže dodat transportní mechanismus, nebo pokud se zpráva musí použít s více než jednou službou, kde každá služba vyžaduje jiný typ přihlašovacích údajů.
Další informace naleznete v tématu Zabezpečení zpráv.
TransportWithMessageCredential
Tato volba používá přenosovou vrstvu k zabezpečení přenosu zpráv, zatímco každá zpráva obsahuje bohaté přihlašovací údaje, které ostatní služby potřebují. To kombinuje výhodu zabezpečení přenosu s bohatou výhodou zabezpečení zpráv. Tato možnost je k dispozici s následujícími vazbami: BasicHttpBinding, WSFederationHttpBindingNetPeerTcpBinding, a WSHttpBinding.
Pokud se rozhodnete použít zabezpečení přenosu pro protokol HTTP (jinými slovy HTTPS), musíte také nakonfigurovat hostitele s certifikátem SSL a povolit SSL na portu. Další informace naleznete v tématu Zabezpečení přenosu PROTOKOLU HTTP.
Pokud používáte WSHttpBinding a nepotřebujete vytvořit zabezpečenou relaci, nastavte EstablishSecurityContext vlastnost na
false
.Zabezpečená relace nastane, když klient a služba vytvoří kanál pomocí symetrického klíče (klient i server používají stejný klíč pro délku konverzace, dokud se dialogové okno neskončí).
Nastavení typu přihlašovacích údajů klienta
Podle potřeby vyberte typ přihlašovacích údajů klienta. Další informace naleznete v tématu Výběr typu přihlašovacích údajů. K dispozici jsou následující typy přihlašovacích údajů klienta:
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
V závislosti na tom, jak režim nastavíte, musíte nastavit typ přihlašovacích údajů. Pokud jste například vybrali wsHttpBinding
a nastavili režim na "Zpráva", můžete také nastavit clientCredentialType
atribut prvku Message na jednu z následujících hodnot: None
, , Windows
, UserName
Certificate
, a IssuedToken
, jak je znázorněno v následujícím příkladu konfigurace.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="myBinding">
<security mode="Message"/>
<message clientCredentialType="Windows"/>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
Nebo v kódu:
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
Nastavení hodnot přihlašovacích údajů služby
Jakmile vyberete typ přihlašovacích údajů klienta, musíte nastavit skutečné přihlašovací údaje pro službu a klienta, které se mají použít. Ve službě jsou přihlašovací údaje nastaveny pomocí ServiceCredentials třídy a vráceny Credentials vlastností ServiceHostBase třídy. Použitá vazba znamená typ přihlašovacích údajů služby, zvolený režim zabezpečení a typ přihlašovacích údajů klienta. Následující kód nastaví certifikát pro přihlašovací údaje služby.
// 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: {0}", ce.Message);
Console.WriteLine();
}
catch (System.Exception exc)
{
Console.WriteLine("An unforeseen error occurred: {0}", 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
Nastavení hodnot přihlašovacích údajů klienta
V klientovi nastavte hodnoty přihlašovacích údajů klienta pomocí ClientCredentials třídy a vrácené ClientCredentials vlastností ClientBase<TChannel> třídy. Následující kód nastaví certifikát jako přihlašovací údaje klienta pomocí protokolu 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 @ {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.
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()