Como: Proteger um serviço com credenciais do Windows

Este tópico mostra como habilitar a segurança de transporte em um serviço WCF (Windows Communication Foundation) que reside em um domínio do Windows e é chamado por clientes no mesmo domínio. Para obter mais informações sobre esse cenário, consulte Segurança de transporte com autenticação do Windows. Para um aplicativo de exemplo, consulte o exemplo WSHttpBinding .

Este tópico pressupõe que você tenha uma interface de contrato existente e uma implementação já definidas, e acrescenta a isso. Você também pode modificar um serviço e um cliente existentes.

Você pode proteger um serviço com credenciais do Windows completamente em código. Como alternativa, você pode omitir parte do código usando um arquivo de configuração. Este tópico mostra os dois sentidos. Certifique-se de usar apenas uma das maneiras, não ambas.

Os três primeiros procedimentos mostram como proteger o serviço usando código. O quarto e quinto procedimento mostra como fazê-lo com um arquivo de configuração.

Usando código

O código completo para o serviço e o cliente está na seção Exemplo no final deste tópico.

O primeiro procedimento percorre a criação e configuração de uma WSHttpBinding classe no código. A associação usa o transporte HTTP. A mesma ligação é usada no cliente.

Para criar um WSHttpBinding que usa credenciais do Windows e segurança de mensagens

  1. O código deste procedimento é inserido no início do Run método da classe no código de Test serviço na seção Exemplo.

  2. Crie uma instância da WSHttpBinding classe.

  3. Defina a Mode WSHttpSecurity propriedade da classe como Message.

  4. Defina a ClientCredentialType MessageSecurityOverHttp propriedade da classe como Windows.

  5. O código para este procedimento é o seguinte:

    // 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
    

Usando a vinculação em um serviço

Este é o segundo procedimento, que mostra como usar a associação em um serviço auto-hospedado. Para obter mais informações sobre serviços de hospedagem, consulte Serviços de hospedagem.

Para usar uma associação em um serviço
  1. Insira o código deste procedimento após o código do procedimento anterior.

  2. Crie uma Type variável chamada contractType e atribua-lhe o tipo de interface (ICalculator). Ao usar o Visual Basic, use o GetType operador ; ao usar C#, use a typeof palavra-chave.

  3. Crie uma segunda Type variável chamada serviceType e atribua-lhe o tipo do contrato implementado (Calculator).

  4. Crie uma instância da Uri classe nomeada baseAddress com o endereço base do serviço. O endereço base deve ter um esquema que corresponda ao transporte. Nesse caso, o esquema de transporte é HTTP, e o endereço inclui o URI (Uniform Resource Identifier) especial "localhost" e um número de porta (8036), bem como um endereço de ponto de extremidade base ("serviceModelSamples/): http://localhost:8036/serviceModelSamples/.

  5. Crie uma instância da ServiceHost classe com as serviceType variáveis e baseAddress .

  6. Adicione um ponto de extremidade ao serviço usando o contractType, vinculação e um nome de ponto de extremidade (secureCalculator). Um cliente deve concatenar o endereço base e o nome do ponto de extremidade ao iniciar uma chamada para o serviço.

  7. Chame o Open método para iniciar o serviço. O código para este procedimento é mostrado aqui:

    // 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()
    

Usando a vinculação em um cliente

Este procedimento mostra como gerar um proxy que se comunica com o serviço. O proxy é gerado com a ServiceModel Metadata Utility Tool (Svcutil.exe), que usa os metadados do serviço para criar o proxy.

Este procedimento também cria uma instância da WSHttpBinding classe para se comunicar com o serviço e, em seguida, chama o serviço.

Este exemplo usa apenas código para criar o cliente. Como alternativa, você pode usar um arquivo de configuração, que é mostrado na seção a seguir a este procedimento.

Para usar uma associação em um cliente com código

  1. Use a ferramenta SvcUtil.exe para gerar o código proxy a partir dos metadados do serviço. Para obter mais informações, consulte Como criar um cliente. O código proxy gerado herda da classe, o ClientBase<TChannel> que garante que cada cliente tenha os construtores, métodos e propriedades necessários para se comunicar com um serviço WCF. Neste exemplo, o código gerado inclui a CalculatorClient classe, que implementa a ICalculator interface, permitindo a compatibilidade com o código de serviço.

  2. O código deste procedimento é inserido no início do Main método do programa cliente.

  3. Crie uma instância da WSHttpBinding classe e defina seu modo de segurança como Message e seu tipo de credencial de cliente como Windows. O exemplo nomeia a variável clientBinding.

  4. Crie uma instância da EndpointAddress classe chamada serviceAddress. Inicialize a instância com o endereço base concatenado com o nome do ponto de extremidade.

  5. Crie uma instância da classe de cliente gerada com as serviceAddress variáveis e clientBinding .

  6. Chame o Open método, conforme mostrado no código a seguir.

  7. Ligue para o serviço e exiba os resultados.

    // 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")
    

Usando o arquivo de configuração

Em vez de criar a associação com código de procedimento, você pode usar o código a seguir mostrado para a seção de ligações do arquivo de configuração.

Se você ainda não tiver um serviço definido, consulte Projetando e implementando serviços e Configurando serviços.

Nota

Esse código de configuração é usado nos arquivos de configuração do serviço e do cliente.

Para habilitar a segurança de transferência em um serviço em um domínio do Windows usando a configuração

  1. Adicione um elemento wsHttpBinding> à< seção do elemento bindings> do arquivo de configuração.<

  2. Adicione um <binding> elemento ao <WSHttpBinding> elemento e defina o configurationName atributo como um valor apropriado para seu aplicativo.

  3. Adicione um <security> elemento e defina o mode atributo como Message.

  4. Adicione um <message> elemento e defina o clientCredentialType atributo como Windows.

  5. No arquivo de configuração do serviço, substitua a <bindings> seção pelo código a seguir. Se você ainda não tiver um arquivo de configuração de serviço, consulte Usando ligações para configurar serviços e clientes.

    <bindings>
      <wsHttpBinding>
       <binding name = "wsHttpBinding_Calculator">
         <security mode="Message">
           <message clientCredentialType="Windows"/>
         </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    

Usando a vinculação em um cliente

Este procedimento mostra como gerar dois arquivos: um proxy que se comunica com o serviço e um arquivo de configuração. Ele também descreve as alterações no programa cliente, que é o terceiro arquivo usado no cliente.

Para usar uma associação em um cliente com configuração

  1. Use a ferramenta SvcUtil.exe para gerar o código proxy e o arquivo de configuração a partir dos metadados do serviço. Para obter mais informações, consulte Como criar um cliente.

  2. Substitua a <seção bindings> do arquivo de configuração gerado pelo código de configuração da seção anterior.

  3. O código de procedimento é inserido no início do Main método do programa cliente.

  4. Crie uma instância da classe de cliente gerada passando o nome da associação no arquivo de configuração como um parâmetro de entrada.

  5. Chame o Open método, conforme mostrado no código a seguir.

  6. Ligue para o serviço e exiba os resultados.

    // 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();
    

Exemplo

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

Consulte também