Procédure : sécuriser un service avec des informations d’identification Windows
Cette rubrique décrit comment activer la sécurité du transport sur un service WCF (Windows Communication Foundation) résidant dans un domaine Windows et appelé par des clients du même domaine. Pour plus d’informations sur ce scénario, consultez Sécurité du transport avec l’authentification Windows. Pour obtenir un exemple d’application, consultez l’exemple WSHttpBinding.
Cette rubrique suppose que vous avez une interface de contrat existante et que l'implémentation est déjà définie et s'ajoute à cela. Vous pouvez également modifier un service et un client existants.
Vous pouvez sécuriser complètement un service avec les informations d'identification Windows dans le code. Vous pouvez également omettre un peu du code en utilisant un fichier de configuration. Cette rubrique décrit les deux approches. Veillez à n'en utiliser qu'une seule, pas les deux.
Les trois premières procédures indiquent comment sécuriser le service à l'aide du code. Les quatrième et cinquième procédures indiquent comment le faire avec un fichier de configuration.
Utilisation du code
L'intégralité du code du service et du client est présentée dans la section Exemple à la fin de cette rubrique.
La première procédure vous guide tout au long de la création et la configuration d'une classe WSHttpBinding dans le code. La liaison utilise le transport HTTP. La même liaison est utilisée sur le client.
Pour créer un WSHttpBinding qui utilise des informations d'identification Windows et la sécurité de message
Le code de cette procédure est inséré au début de la méthode
Run
de la classeTest
dans le code de service indiqué à la section Exemple.Créez une instance de la classe WSHttpBinding.
Affectez la valeur Mode à la propriété WSHttpSecurity de la classe Message.
Affectez la valeur ClientCredentialType à la propriété MessageSecurityOverHttp de la classe Windows.
Le code de cette procédure se présente comme suit :
// First procedure: // create a WSHttpBinding that uses Windows credentials and message security WSHttpBinding myBinding = new WSHttpBinding(); myBinding.Security.Mode = SecurityMode.Message; myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
Dim myBinding As New WSHttpBinding() myBinding.Security.Mode = SecurityMode.Message myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows
Utilisation de la liaison dans un service
Il s’agit de la deuxième procédure, qui indique comment utiliser la liaison dans un service auto-hébergé. Pour plus d’informations sur l’hébergement des services, consultez Hébergement de services.
Pour utiliser une liaison dans un service
Insérez le code de cette procédure après celui de la procédure précédente.
Créez une variable Type nommée
contractType
et assignez-lui le type de l'interface (ICalculator
). Lorsque vous utilisez Visual Basic, utilisez l’opérateurGetType
; lorsque vous utilisez C#, utilisez le mot clétypeof
.Créez une deuxième variable Type nommée
serviceType
et assignez-lui le type du contrat implémenté (Calculator
).Créez une instance de la classe Uri nommée
baseAddress
avec l'adresse de base du service. L'adresse de base doit avoir un schéma qui correspond au transport. Dans ce cas, le schéma de transport est HTTP et l’adresse inclut l’URI (Uniform Resource Identifier) spécial « localhost » et un numéro de port (8036), ainsi qu’une adresse de point de terminaison de base (serviceModelSamples/) :http://localhost:8036/serviceModelSamples/
.Créez une instance de la classe ServiceHost avec les variables
serviceType
etbaseAddress
.Ajoutez un point de terminaison au service à l'aide du
contractType
, de la liaison et d'un nom de point de terminaison (secureCalculator). Un client doit concaténer l'adresse de base et le nom de point de terminaison lors du lancement d'un appel au service.Appelez la méthode Open pour démarrer le service. Le code de cette procédure est indiqué ici :
// 2nd Procedure: // Use the binding in a service // Create the Type instances for later use and the URI for // the base address. Type contractType = typeof(ICalculator); Type serviceType = typeof(Calculator); Uri baseAddress = new Uri("http://localhost:8036/SecuritySamples/"); // Create the ServiceHost and add an endpoint, then start // the service. ServiceHost myServiceHost = new ServiceHost(serviceType, baseAddress); myServiceHost.AddServiceEndpoint (contractType, myBinding, "secureCalculator"); //enable metadata ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; myServiceHost.Description.Behaviors.Add(smb); myServiceHost.Open();
' Create the Type instances for later use and the URI for ' the base address. Dim contractType As Type = GetType(ICalculator) Dim serviceType As Type = GetType(Calculator) Dim baseAddress As New Uri("http://localhost:8036/serviceModelSamples/") ' Create the ServiceHost and add an endpoint, then start ' the service. Dim myServiceHost As New ServiceHost(serviceType, baseAddress) myServiceHost.AddServiceEndpoint(contractType, myBinding, "secureCalculator") myServiceHost.Open()
Utilisation de la liaison sur un client
Cette procédure indique comment générer un proxy qui communique avec le service. Le proxy est généré avec l’outil ServiceModel Metadata Utility (Svcutil.exe) qui utilise les métadonnées du service pour créer le proxy.
Cette procédure crée également une instance de la classe WSHttpBinding pour communiquer avec le service, puis appelle ce dernier.
Cet exemple utilise uniquement du code pour créer le client. Vous pouvez aussi, si vous le souhaitez, utiliser un fichier de configuration, indiqué dans la section qui suit cette procédure.
Pour utiliser une liaison sur un client avec le code
Utilisez l'outil SvcUtil.exe pour générer le code du proxy à partir des métadonnées du service. Pour plus d’informations, consultez Guide pratique pour créer un client. Le code du proxy généré hérite de la classe ClientBase<TChannel>, ce qui garantit que chaque client possède les constructeurs, méthodes et propriétés nécessaires pour communiquer avec un service WCF. Dans cet exemple, le code généré inclut la classe
CalculatorClient
, qui implémente l'interfaceICalculator
, activant ainsi la compatibilité avec le code de service.Le code de cette procédure est inséré au début de la méthode
Main
du programme client.Créez une instance de la classe WSHttpBinding et affectez à son mode de sécurité la valeur
Message
et à son type d'informations d'identification client la valeurWindows
. L'exemple nomme la variableclientBinding
.Créez une instance de la classe EndpointAddress nommée
serviceAddress
. Initialisez l'instance avec l'adresse de base concaténée avec le nom de point de terminaison.Créez une instance de la classe de client générée avec les variables
serviceAddress
etclientBinding
.Appelez la méthode Open, comme illustré dans le code suivant :
Appelez le service et affichez les résultats.
// 3rd Procedure: // Creating a binding and using it in a service // To run using config, comment the following lines, and uncomment out the code // following this section WSHttpBinding b = new WSHttpBinding(SecurityMode.Message); b.Security.Message.ClientCredentialType = MessageCredentialType.Windows; EndpointAddress ea = new EndpointAddress("Http://localhost:8036/SecuritySamples/secureCalculator"); CalculatorClient cc = new CalculatorClient(b, ea); cc.Open(); // Now call the service and display the results // Call the Add service operation. double value1 = 100.00D; double value2 = 15.99D; double result = cc.Add(value1, value2); Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result); // Closing the client gracefully closes the connection and cleans up resources. cc.Close();
Dim b As New WSHttpBinding(SecurityMode.Message) b.Security.Message.ClientCredentialType = MessageCredentialType.Windows Dim ea As New EndpointAddress("net.tcp://machinename:8036/endpoint") Dim cc As New CalculatorClient(b, ea) cc.Open() ' Alternatively, use a binding name from a configuration file generated by the ' SvcUtil.exe tool to create the client. Omit the binding and endpoint address ' because that information is provided by the configuration file. ' CalculatorClass cc = new CalculatorClient("ICalculator_Binding")
Utilisation du fichier de configuration
Au lieu de créer la liaison avec le code de procédure, vous pouvez utiliser le code suivant indiqué pour la section Liaisons du fichier de configuration.
Si vous n’avez pas encore de service défini, consultez Conception et implémentation de services et Configuration de services.
Notes
Ce code de configuration est utilisé dans les fichiers de configuration du service et du client.
Pour activer la sécurité de transfert sur un service dans un domaine Windows à l'aide de la configuration
Ajoutez un élément <wsHttpBinding> à la section d’éléments <bindings> du fichier de configuration.
Ajoutez un élément
<binding>
à l’élément<WSHttpBinding>
et affectez à l’attributconfigurationName
une valeur appropriée pour votre application.Ajoutez un élément
<security>
et affectez à l’attributmode
la valeur Message.Ajoutez un élément
<message>
et affectez à l’attributclientCredentialType
la valeur Windows.Dans le fichier de configuration du service, remplacez la section
<bindings>
par le code suivant. Si vous n’avez pas encore de fichier de configuration de service, consultez Utilisation de liaisons pour configurer des services et des clients.<bindings> <wsHttpBinding> <binding name = "wsHttpBinding_Calculator"> <security mode="Message"> <message clientCredentialType="Windows"/> </security> </binding> </wsHttpBinding> </bindings>
Utilisation de la liaison sur un client
Cette procédure indique comment générer deux fichiers : un proxy qui communique avec le service et un fichier de configuration. Elle décrit également les modifications du programme client, qui est le troisième fichier utilisé sur le client.
Pour utiliser une liaison sur un client avec la configuration
Utilisez l'outil SvcUtil.exe pour générer le code proxy et le fichier de configuration à partir des métadonnées du service. Pour plus d’informations, consultez Guide pratique pour créer un client.
Remplacez la section <bindings> du fichier de configuration généré par le code de configuration de la section précédente.
Le code de la procédure est inséré au début de la méthode
Main
du programme client.Créez une instance de la classe de client générée qui passe le nom de la liaison dans le fichier de configuration comme un paramètre d'entrée.
Appelez la méthode Open, comme illustré dans le code suivant :
Appelez le service et affichez les résultats.
// 4th Procedure: // Using config instead of the binding-related code // In this case, use a binding name from a configuration file generated by the // SvcUtil.exe tool to create the client. Omit the binding and endpoint address // because that information is provided by the configuration file. CalculatorClient cc = new CalculatorClient("ICalculator_Binding"); cc.Open(); // Now call the service and display the results // Call the Add service operation. double value1 = 100.00D; double value2 = 15.99D; double result = cc.Add(value1, value2); Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result); // Closing the client gracefully closes the connection and cleans up resources. cc.Close();
Exemple
using System;
using System.Collections;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace Microsoft.Security.Samples
{
public class Test
{
static void Main()
{
Test t = new Test();
Console.WriteLine("Starting....");
t.Run();
}
private void Run()
{
// First procedure:
// create a WSHttpBinding that uses Windows credentials and message security
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType =
MessageCredentialType.Windows;
// 2nd Procedure:
// Use the binding in a service
// Create the Type instances for later use and the URI for
// the base address.
Type contractType = typeof(ICalculator);
Type serviceType = typeof(Calculator);
Uri baseAddress = new
Uri("http://localhost:8036/SecuritySamples/");
// Create the ServiceHost and add an endpoint, then start
// the service.
ServiceHost myServiceHost =
new ServiceHost(serviceType, baseAddress);
myServiceHost.AddServiceEndpoint
(contractType, myBinding, "secureCalculator");
//enable metadata
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
myServiceHost.Description.Behaviors.Add(smb);
myServiceHost.Open();
Console.WriteLine("Listening");
Console.WriteLine("Press Enter to close the service");
Console.ReadLine();
myServiceHost.Close();
}
}
[ServiceContract]
public interface ICalculator
{
[OperationContract]
double Add(double a, double b);
}
public class Calculator : ICalculator
{
public double Add(double a, double b)
{
return a + b;
}
}
}
using System;
using System.Collections.Generic;
using System.ServiceModel;
namespace Client
{
static class SecureClientCode
{
static void Main()
{
// 3rd Procedure:
// Creating a binding and using it in a service
// To run using config, comment the following lines, and uncomment out the code
// following this section
WSHttpBinding b = new WSHttpBinding(SecurityMode.Message);
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
EndpointAddress ea = new EndpointAddress("Http://localhost:8036/SecuritySamples/secureCalculator");
CalculatorClient cc = new CalculatorClient(b, ea);
cc.Open();
// Now call the service and display the results
// Call the Add service operation.
double value1 = 100.00D;
double value2 = 15.99D;
double result = cc.Add(value1, value2);
Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
// Closing the client gracefully closes the connection and cleans up resources.
cc.Close();
}
static void Main2()
{
// 4th Procedure:
// Using config instead of the binding-related code
// In this case, use a binding name from a configuration file generated by the
// SvcUtil.exe tool to create the client. Omit the binding and endpoint address
// because that information is provided by the configuration file.
CalculatorClient cc = new CalculatorClient("ICalculator_Binding");
cc.Open();
// Now call the service and display the results
// Call the Add service operation.
double value1 = 100.00D;
double value2 = 15.99D;
double result = cc.Add(value1, value2);
Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
// Closing the client gracefully closes the connection and cleans up resources.
cc.Close();
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://Microsoft.ServiceModel.Samples", ConfigurationName = "ICalculator")]
public interface ICalculator
{
[System.ServiceModel.OperationContractAttribute(Action = "http://Microsoft.ServiceModel.Samples/ICalculator/Add", ReplyAction = "http://Microsoft.ServiceModel.Samples/ICalculator/AddResponse")]
double Add(double n1, double n2);
[System.ServiceModel.OperationContractAttribute(Action = "http://Microsoft.ServiceModel.Samples/ICalculator/Subtract", ReplyAction = "http://Microsoft.ServiceModel.Samples/ICalculator/SubtractResponse")]
double Subtract(double n1, double n2);
[System.ServiceModel.OperationContractAttribute(Action = "http://Microsoft.ServiceModel.Samples/ICalculator/Multiply", ReplyAction = "http://Microsoft.ServiceModel.Samples/ICalculator/MultiplyResponse")]
double Multiply(double n1, double n2);
[System.ServiceModel.OperationContractAttribute(Action = "http://Microsoft.ServiceModel.Samples/ICalculator/Divide", ReplyAction = "http://Microsoft.ServiceModel.Samples/ICalculator/DivideResponse")]
double Divide(double n1, double n2);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface ICalculatorChannel : ICalculator, System.ServiceModel.IClientChannel
{
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public class CalculatorClient : System.ServiceModel.ClientBase<ICalculator>, ICalculator
{
public CalculatorClient()
{
}
public CalculatorClient(string endpointConfigurationName)
:
base(endpointConfigurationName)
{
}
public CalculatorClient(string endpointConfigurationName, string remoteAddress)
:
base(endpointConfigurationName, remoteAddress)
{
}
public CalculatorClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
:
base(endpointConfigurationName, remoteAddress)
{
}
public CalculatorClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress)
:
base(binding, remoteAddress)
{
}
public double Add(double n1, double n2)
{
return base.Channel.Add(n1, n2);
}
public double Subtract(double n1, double n2)
{
return base.Channel.Subtract(n1, n2);
}
public double Multiply(double n1, double n2)
{
return base.Channel.Multiply(n1, n2);
}
public double Divide(double n1, double n2)
{
return base.Channel.Divide(n1, n2);
}
}
}
Imports System.Collections.Generic
Imports System.ServiceModel
Public Class Program
Shared Sub Main()
Dim b As New WSHttpBinding(SecurityMode.Message)
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
Dim ea As New EndpointAddress("net.tcp://machinename:8036/endpoint")
Dim cc As New CalculatorClient(b, ea)
cc.Open()
' Alternatively, use a binding name from a configuration file generated by the
' SvcUtil.exe tool to create the client. Omit the binding and endpoint address
' because that information is provided by the configuration file.
' CalculatorClass cc = new CalculatorClient("ICalculator_Binding")
End Sub
End Class
<System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0"), System.ServiceModel.ServiceContractAttribute([Namespace]:="http://Microsoft.ServiceModel.Samples", ConfigurationName:="ICalculator")> _
Public Interface ICalculator
<System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Add", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/AddResponse")> _
Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double
<System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Subtract", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/SubtractResponse")> _
Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double
<System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Multiply", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/MultiplyResponse")> _
Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double
<System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Divide", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/DivideResponse")> _
Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double
End Interface 'ICalculator
<System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")> _
Public Interface ICalculatorChannel
: Inherits ICalculator, System.ServiceModel.IClientChannel
End Interface 'ICalculatorChannel
<System.Diagnostics.DebuggerStepThroughAttribute(), System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")> _
Public Class CalculatorClient
Inherits System.ServiceModel.ClientBase(Of ICalculator)
Implements ICalculator
Public Sub New()
'
End Sub
Public Sub New(ByVal endpointConfigurationName As String)
MyBase.New(endpointConfigurationName)
End Sub
Public Sub New(ByVal endpointConfigurationName As String, ByVal remoteAddress As String)
MyBase.New(endpointConfigurationName, remoteAddress)
End Sub
Public Sub New(ByVal endpointConfigurationName As String, ByVal remoteAddress As System.ServiceModel.EndpointAddress)
MyBase.New(endpointConfigurationName, remoteAddress)
End Sub
Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, ByVal remoteAddress As System.ServiceModel.EndpointAddress)
MyBase.New(binding, remoteAddress)
End Sub
Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Add
Return MyBase.Channel.Add(n1, n2)
End Function 'Add
Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Subtract
Return MyBase.Channel.Subtract(n1, n2)
End Function 'Subtract
Public Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Multiply
Return MyBase.Channel.Multiply(n1, n2)
End Function 'Multiply
Public Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Divide
Return MyBase.Channel.Divide(n1, n2)
End Function 'Divide
End Class