Instrukcje: Zabezpieczanie usługi za pomocą poświadczeń systemu Windows
W tym temacie przedstawiono sposób włączania zabezpieczeń transportu w usłudze Windows Communication Foundation (WCF), która znajduje się w domenie systemu Windows i jest wywoływana przez klientów w tej samej domenie. Aby uzyskać więcej informacji na temat tego scenariusza, zobacz Transport Security with Windows Authentication (Zabezpieczenia transportu przy użyciu uwierzytelniania systemu Windows). Aby zapoznać się z przykładową aplikacją, zobacz przykład WSHttpBinding .
W tym temacie przyjęto założenie, że masz już zdefiniowany interfejs kontraktu i implementację oraz dodano do tego. Możesz również zmodyfikować istniejącą usługę i klienta.
Usługę można zabezpieczyć za pomocą poświadczeń systemu Windows całkowicie w kodzie. Alternatywnie można pominąć część kodu przy użyciu pliku konfiguracji. W tym temacie przedstawiono oba sposoby. Upewnij się, że używasz tylko jednego ze sposobów, a nie obu.
Pierwsze trzy procedury pokazują, jak zabezpieczyć usługę przy użyciu kodu. Czwarta i piąta procedura pokazuje, jak to zrobić z plikiem konfiguracji.
Korzystanie z kodu
Pełny kod usługi i klient znajduje się w sekcji Przykład na końcu tego tematu.
Pierwsza procedura przeprowadzi cię przez proces tworzenia i konfigurowania WSHttpBinding klasy w kodzie. Powiązanie używa transportu HTTP. To samo powiązanie jest używane na kliencie.
Aby utworzyć usługę WSHttpBinding korzystającą z poświadczeń systemu Windows i zabezpieczeń komunikatów
Kod tej procedury jest wstawiany na początku
Run
metodyTest
klasy w kodzie usługi w sekcji Przykład.Utworzenie wystąpienia WSHttpBinding klasy.
Mode Ustaw właściwość WSHttpSecurity klasy na Message.
ClientCredentialType Ustaw właściwość MessageSecurityOverHttp klasy na Windows.
Kod tej procedury jest następujący:
// 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
Używanie powiązania w usłudze
Jest to druga procedura, która pokazuje, jak używać powiązania w samoobsługowej usłudze. Aby uzyskać więcej informacji na temat usług hostingowych, zobacz Hosting Services.
Aby użyć powiązania w usłudze
Wstaw kod tej procedury po kodzie z poprzedniej procedury.
Utwórz zmienną Type o nazwie
contractType
i przypisz jej typ interfejsu (ICalculator
). W przypadku korzystania z języka Visual Basic użyjGetType
operatora ; w przypadku korzystania z języka C#użyj słowa kluczowegotypeof
.Utwórz drugą Type zmienną o nazwie
serviceType
i przypisz jej typ zaimplementowanego kontraktu (Calculator
).Utwórz wystąpienie Uri klasy o nazwie przy użyciu
baseAddress
podstawowego adresu usługi. Adres podstawowy musi mieć schemat zgodny z transportem. W takim przypadku schemat transportu to HTTP, a adres zawiera specjalny identyfikator URI (URI) "localhost" i numer portu (8036), a także podstawowy adres punktu końcowego ("serviceModelSamples/):http://localhost:8036/serviceModelSamples/
.Utwórz wystąpienie ServiceHost klasy za pomocą
serviceType
zmiennych ibaseAddress
.Dodaj punkt końcowy do usługi przy użyciu nazwy punktu końcowego
contractType
, powiązania i punktu końcowego (secureCalculator). Klient musi połączyć adres podstawowy i nazwę punktu końcowego podczas inicjowania wywołania usługi.Wywołaj metodę Open , aby uruchomić usługę. Kod tej procedury jest pokazany tutaj:
// 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()
Używanie powiązania w kliencie
Ta procedura pokazuje, jak wygenerować serwer proxy, który komunikuje się z usługą. Serwer proxy jest generowany za pomocą narzędzia ServiceModel Metadata Tool (Svcutil.exe), który używa metadanych usługi do tworzenia serwera proxy.
Ta procedura tworzy również wystąpienie WSHttpBinding klasy w celu komunikowania się z usługą, a następnie wywołuje usługę.
W tym przykładzie użyto tylko kodu do utworzenia klienta. Alternatywnie możesz użyć pliku konfiguracji pokazanego w sekcji opisanej w tej procedurze.
Aby użyć powiązania w kliencie z kodem
Użyj narzędzia SvcUtil.exe, aby wygenerować kod serwera proxy na podstawie metadanych usługi. Aby uzyskać więcej informacji, zobacz How to: Create a Client (Instrukcje: tworzenie klienta). Wygenerowany kod serwera proxy dziedziczy z ClientBase<TChannel> klasy, co gwarantuje, że każdy klient ma niezbędne konstruktory, metody i właściwości do komunikowania się z usługą WCF. W tym przykładzie wygenerowany kod zawiera klasę
CalculatorClient
, która implementujeICalculator
interfejs, umożliwiając zgodność z kodem usługi.Kod tej procedury jest wstawiany na początku
Main
metody programu klienckiego.Utwórz wystąpienie WSHttpBinding klasy i ustaw jego tryb zabezpieczeń na
Message
i jego typ poświadczeń klienta naWindows
. Przykład nazywa zmiennąclientBinding
.Utwórz wystąpienie EndpointAddress klasy o nazwie
serviceAddress
. Zainicjuj wystąpienie przy użyciu adresu podstawowego z nazwą punktu końcowego.Utwórz wystąpienie wygenerowanej klasy klienta za pomocą
serviceAddress
zmiennych iclientBinding
.Wywołaj metodę Open , jak pokazano w poniższym kodzie.
Wywołaj usługę i wyświetl wyniki.
// 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")
Korzystanie z pliku konfiguracji
Zamiast tworzyć powiązanie za pomocą kodu proceduralnego, możesz użyć następującego kodu pokazanego dla sekcji powiązań pliku konfiguracji.
Jeśli nie masz jeszcze zdefiniowanej usługi, zobacz Projektowanie i implementowanie usług oraz Konfigurowanie usług.
Uwaga
Ten kod konfiguracji jest używany zarówno w plikach konfiguracji usługi, jak i klienta.
Aby włączyć zabezpieczenia transferu w usłudze w domenie systemu Windows przy użyciu konfiguracji
<Dodaj element wsHttpBinding> do <sekcji elementu bindings> pliku konfiguracji.
<binding>
Dodaj element do<WSHttpBinding>
elementu i ustawconfigurationName
atrybut na wartość odpowiednią dla aplikacji.<security>
Dodaj element i ustaw atrybut namode
Message.<message>
Dodaj element i ustawclientCredentialType
atrybut na Windows.W pliku konfiguracji usługi zastąp sekcję
<bindings>
następującym kodem. Jeśli nie masz jeszcze pliku konfiguracji usługi, zobacz Konfigurowanie usług i klientów przy użyciu powiązań.<bindings> <wsHttpBinding> <binding name = "wsHttpBinding_Calculator"> <security mode="Message"> <message clientCredentialType="Windows"/> </security> </binding> </wsHttpBinding> </bindings>
Używanie powiązania w kliencie
Ta procedura przedstawia sposób generowania dwóch plików: serwera proxy komunikującego się z usługą i plikiem konfiguracji. Opisuje również zmiany w programie klienckim, który jest trzecim plikiem używanym na kliencie.
Aby użyć powiązania w kliencie z konfiguracją
Użyj narzędzia SvcUtil.exe, aby wygenerować kod serwera proxy i plik konfiguracji na podstawie metadanych usługi. Aby uzyskać więcej informacji, zobacz How to: Create a Client (Instrukcje: tworzenie klienta).
Zastąp sekcję <powiązań> wygenerowanego pliku konfiguracji kodem konfiguracji z poprzedniej sekcji.
Kod proceduralny jest wstawiany na początku
Main
metody programu klienckiego.Utwórz wystąpienie wygenerowanej klasy klienta przekazujące nazwę powiązania w pliku konfiguracji jako parametr wejściowy.
Wywołaj metodę Open , jak pokazano w poniższym kodzie.
Wywołaj usługę i wyświetl wyniki.
// 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();
Przykład
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