Procedure: Een service beveiligen met Windows-referenties
In dit onderwerp wordt beschreven hoe u transportbeveiliging inschakelt voor een WCF-service (Windows Communication Foundation) die zich in een Windows-domein bevindt en wordt aangeroepen door clients in hetzelfde domein. Zie Transportbeveiliging met Windows-verificatie voor meer informatie over dit scenario. Zie het WSHttpBinding-voorbeeld voor een voorbeeldtoepassing.
In dit onderwerp wordt ervan uitgegaan dat u een bestaande contractinterface en -implementatie hebt gedefinieerd en hieraan toevoegt. U kunt ook een bestaande service en client wijzigen.
U kunt een service beveiligen met Windows-referenties volledig in code. U kunt ook een deel van de code weglaten met behulp van een configuratiebestand. In dit onderwerp worden beide manieren beschreven. Zorg ervoor dat u slechts een van de manieren gebruikt, niet beide.
De eerste drie procedures laten zien hoe u de service beveiligt met behulp van code. In de vierde en vijfde procedure ziet u hoe u dit doet met een configuratiebestand.
Code gebruiken
De volledige code voor de service en de client bevindt zich in de sectie Voorbeeld aan het einde van dit onderwerp.
De eerste procedure helpt bij het maken en configureren van een WSHttpBinding klasse in code. De binding maakt gebruik van het HTTP-transport. Dezelfde binding wordt op de client gebruikt.
Een WSHttpBinding maken die gebruikmaakt van Windows-referenties en berichtbeveiliging
De code van deze procedure wordt ingevoegd aan het begin van de methode van de
Run
Test
klasse in de servicecode in de sectie Voorbeeld.Maak een exemplaar van de WSHttpBinding-klasse.
Stel de Mode eigenschap van de WSHttpSecurity klasse in op Message.
Stel de ClientCredentialType eigenschap van de MessageSecurityOverHttp klasse in op Windows.
De code voor deze procedure is als volgt:
// 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
De binding in een service gebruiken
Dit is de tweede procedure, die laat zien hoe u de binding gebruikt in een zelf-hostende service. Zie Hostingservices voor meer informatie over hostingservices.
Een binding gebruiken in een service
Voeg de code van deze procedure in na de code uit de voorgaande procedure.
Maak een Type variabele met de naam
contractType
en wijs deze toe aan het type interface (ICalculator
). Wanneer u Visual Basic gebruikt, gebruikt u deGetType
operator; wanneer u C# gebruikt, gebruikt u hettypeof
trefwoord.Maak een tweede Type variabele met de naam
serviceType
en wijs deze toe aan het type geïmplementeerde contract (Calculator
).Maak een exemplaar van de klasse met de Uri naam
baseAddress
met het basisadres van de service. Het basisadres moet een schema hebben dat overeenkomt met het transport. In dit geval is het transportschema HTTP en bevat het adres de speciale URI (Uniform Resource Identifier) 'localhost' en een poortnummer (8036) en een basiseindpuntadres (serviceModelSamples/):http://localhost:8036/serviceModelSamples/
.Maak een exemplaar van de ServiceHost klasse met de
serviceType
enbaseAddress
variabelen.Voeg een eindpunt toe aan de service met behulp van de
contractType
naam, binding en een eindpuntnaam (secureCalculator). Een client moet het basisadres en de eindpuntnaam samenvoegen bij het initiëren van een aanroep naar de service.Roep de Open methode aan om de service te starten. De code voor deze procedure wordt hier weergegeven:
// 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()
De binding in een client gebruiken
Deze procedure laat zien hoe u een proxy genereert die communiceert met de service. De proxy wordt gegenereerd met het hulpprogramma ServiceModel Metadata Utility (Svcutil.exe) dat gebruikmaakt van de metagegevens van de service om de proxy te maken.
Met deze procedure maakt u ook een exemplaar van de WSHttpBinding klasse om met de service te communiceren en roept u vervolgens de service aan.
In dit voorbeeld wordt alleen code gebruikt om de client te maken. Als alternatief kunt u een configuratiebestand gebruiken, dat wordt weergegeven in de sectie na deze procedure.
Een binding gebruiken in een client met code
Gebruik het hulpprogramma SvcUtil.exe om de proxycode te genereren op basis van de metagegevens van de service. Zie Een client maken voor meer informatie. De gegenereerde proxycode neemt over van de ClientBase<TChannel> klasse, die ervoor zorgt dat elke client beschikt over de benodigde constructors, methoden en eigenschappen om te communiceren met een WCF-service. In dit voorbeeld bevat de gegenereerde code de
CalculatorClient
klasse, waarmee deICalculator
interface wordt geïmplementeerd, waardoor compatibiliteit met de servicecode mogelijk is.De code van deze procedure wordt ingevoegd aan het begin van de
Main
methode van het clientprogramma.Maak een exemplaar van de WSHttpBinding klasse en stel de beveiligingsmodus
Message
in op en het clientreferentietype opWindows
. In het voorbeeld wordt de variabeleclientBinding
genoemd.Maak een exemplaar van de klasse met de EndpointAddress naam
serviceAddress
. Initialiseer het exemplaar met het basisadres dat is samengevoegd met de eindpuntnaam.Maak een exemplaar van de gegenereerde clientklasse met de
serviceAddress
en declientBinding
variabelen.Roep de Open methode aan, zoals wordt weergegeven in de volgende code.
Roep de service aan en geef de resultaten weer.
// 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")
Het configuratiebestand gebruiken
In plaats van de binding met procedurele code te maken, kunt u de volgende code gebruiken die wordt weergegeven voor de sectie bindingen van het configuratiebestand.
Als u nog geen service hebt gedefinieerd, raadpleegt u Services ontwerpen en implementeren en Services configureren.
Notitie
Deze configuratiecode wordt gebruikt in zowel de service- als clientconfiguratiebestanden.
Overdrachtsbeveiliging inschakelen voor een service in een Windows-domein met behulp van configuratie
Voeg een wsHttpBinding-element> toe aan de< sectie bindingselement> van het configuratiebestand.<
Voeg een
<binding>
element toe aan het<WSHttpBinding>
element en stel hetconfigurationName
kenmerk in op een waarde die geschikt is voor uw toepassing.Voeg een
<security>
element toe en stel hetmode
kenmerk in op Bericht.Voeg een
<message>
element toe en stel hetclientCredentialType
kenmerk in op Windows.Vervang in het configuratiebestand van de service de
<bindings>
sectie door de volgende code. Als u nog geen serviceconfiguratiebestand hebt, raadpleegt u Bindingen gebruiken om services en clients te configureren.<bindings> <wsHttpBinding> <binding name = "wsHttpBinding_Calculator"> <security mode="Message"> <message clientCredentialType="Windows"/> </security> </binding> </wsHttpBinding> </bindings>
De binding in een client gebruiken
In deze procedure ziet u hoe u twee bestanden genereert: een proxy die communiceert met de service en een configuratiebestand. Ook worden wijzigingen in het clientprogramma beschreven. Dit is het derde bestand dat op de client wordt gebruikt.
Een binding gebruiken in een client met configuratie
Gebruik het hulpprogramma SvcUtil.exe om de proxycode en het configuratiebestand te genereren op basis van de metagegevens van de service. Zie Een client maken voor meer informatie.
Vervang de <bindingensectie> van het gegenereerde configuratiebestand door de configuratiecode uit de vorige sectie.
Procedurele code wordt ingevoegd aan het begin van de
Main
methode van het clientprogramma.Maak een exemplaar van de gegenereerde clientklasse die de naam van de binding doorgeeft in het configuratiebestand als invoerparameter.
Roep de Open methode aan, zoals wordt weergegeven in de volgende code.
Roep de service aan en geef de resultaten weer.
// 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();
Voorbeeld
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