Partilhar via


Passo a passo: Criando credenciais personalizadas de cliente e serviço

Este tópico mostra como implementar credenciais personalizadas de cliente e serviço e como usar credenciais personalizadas do código do aplicativo.

Classes de extensibilidade de credenciais

As ClientCredentials classes e ServiceCredentials são os principais pontos de entrada para a extensibilidade de segurança do Windows Communication Foundation (WCF). Essas classes de credenciais fornecem as APIs que permitem que o código do aplicativo defina informações de credenciais e converta tipos de credenciais em tokens de segurança. (Os tokens de segurança são o formulário usado para transmitir informações de credenciais dentro de mensagens SOAP.) As responsabilidades dessas classes de credenciais podem ser divididas em duas áreas:

  • Forneça as APIs para que os aplicativos definam informações de credenciais.

  • Atuar como fábrica de SecurityTokenManager implementações.

As implementações padrão fornecidas no WCF oferecem suporte aos tipos de credenciais fornecidos pelo sistema e criam um gerenciador de token de segurança capaz de lidar com esses tipos de credenciais.

Razões para personalizar

Há vários motivos para personalizar classes de credenciais de cliente ou serviço. O principal é o requisito para alterar o comportamento de segurança padrão do WCF em relação ao tratamento de tipos de credenciais fornecidos pelo sistema, especialmente pelos seguintes motivos:

  • Alterações que não são possíveis usando outros pontos de extensibilidade.

  • Adicionar novos tipos de credenciais.

  • Adicionar novos tipos de token de segurança personalizados.

Este tópico descreve como implementar credenciais personalizadas de cliente e serviço e como usá-las a partir do código do aplicativo.

Primeiro de uma série

Criar uma classe de credenciais personalizadas é apenas a primeira etapa, porque o motivo para personalizar credenciais é alterar o comportamento do WCF em relação ao provisionamento de credenciais, serialização de token de segurança ou autenticação. Outros tópicos nesta seção descrevem como criar serializadores e autenticadores personalizados. Nesse sentido, a criação de uma classe de credencial personalizada é o primeiro tópico da série. As ações subsequentes (criação de serializadores e autenticadores personalizados) podem ser feitas somente após a criação de credenciais personalizadas. Outros tópicos que se baseiam neste tópico incluem:

Procedimentos

Para implementar credenciais de cliente personalizadas

  1. Defina uma nova classe derivada da ClientCredentials classe.

  2. Opcional. Adicione novos métodos ou propriedades para novos tipos de credenciais. Se você não adicionar novos tipos de credenciais, ignore esta etapa. O exemplo a seguir adiciona uma CreditCardNumber propriedade.

  3. Substitua o CreateSecurityTokenManager método. Esse método é chamado automaticamente pela infraestrutura de segurança do WCF quando a credencial de cliente personalizada é usada. Esse método é responsável por criar e retornar uma instância de uma implementação da SecurityTokenManager classe.

    Importante

    É importante observar que o CreateSecurityTokenManager método é substituído para criar um gerenciador de token de segurança personalizado. O gerenciador de token de segurança, derivado de ClientCredentialsSecurityTokenManager, deve retornar um provedor de token de segurança personalizado, derivado de SecurityTokenProvider, para criar o token de segurança real. Se você não seguir esse padrão para criar tokens de segurança, seu aplicativo pode funcionar incorretamente quando ChannelFactory os objetos são armazenados em cache (que é o comportamento padrão para proxies de cliente WCF), potencialmente resultando em um ataque de elevação de privilégio. O objeto de credencial personalizado é armazenado em cache como parte do ChannelFactory. No entanto, o costume SecurityTokenManager é criado em cada invocação, o que atenua a ameaça à segurança, desde que a lógica de criação do token seja colocada no SecurityTokenManager.

  4. Substitua o CloneCore método.

    public class MyClientCredentials : ClientCredentials
    {
        string creditCardNumber;
    
        public MyClientCredentials()
        {
            // Perform client credentials initialization.
        }
    
        protected MyClientCredentials(MyClientCredentials other)
            : base(other)
        {
            // Clone fields defined in this class.
            this.creditCardNumber = other.creditCardNumber;
        }
    
        public string CreditCardNumber
        {
            get
            {
                return this.creditCardNumber;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                this.creditCardNumber = value;
            }
        }
    
        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            // Return your implementation of the SecurityTokenManager.
            return new MyClientCredentialsSecurityTokenManager(this);
        }
    
        protected override ClientCredentials CloneCore()
        {
            // Implement the cloning functionality.
            return new MyClientCredentials(this);
        }
    }
    
    Public Class MyClientCredentials
        Inherits ClientCredentials
        Private creditCardNumberValue As String
    
        Public Sub New()
    
        End Sub
    
        ' Perform client credentials initialization.    
        Protected Sub New(ByVal other As MyClientCredentials)
            MyBase.New(other)
            ' Clone fields defined in this class.
            Me.creditCardNumberValue = other.creditCardNumberValue
    
        End Sub
    
        Public Property CreditCardNumber() As String
            Get
                Return Me.creditCardNumberValue
            End Get
            Set
                If value Is Nothing Then
                    Throw New ArgumentNullException("value")
                End If
                Me.creditCardNumberValue = value
            End Set
        End Property
    
        Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager
            ' Return your implementation of the SecurityTokenManager.
            Return New MyClientCredentialsSecurityTokenManager(Me)
    
        End Function
    
        Protected Overrides Function CloneCore() As ClientCredentials
            ' Implement the cloning functionality.
            Return New MyClientCredentials(Me)
    
        End Function
    End Class
    

Para implementar um gerenciador de token de segurança de cliente personalizado

  1. Defina uma nova classe derivada de ClientCredentialsSecurityTokenManager.

  2. Opcional. Substitua o CreateSecurityTokenProvider(SecurityTokenRequirement) método se uma implementação personalizada SecurityTokenProvider deve ser criada. Para obter mais informações sobre provedores de token de segurança personalizados, consulte Como criar um provedor de token de segurança personalizado.

  3. Opcional. Substitua o CreateSecurityTokenAuthenticator(SecurityTokenRequirement, SecurityTokenResolver) método se uma implementação personalizada SecurityTokenAuthenticator deve ser criada. Para obter mais informações sobre autenticadores de token de segurança personalizados, consulte Como criar um autenticador de token de segurança personalizado.

  4. Opcional. Substitua o CreateSecurityTokenSerializer método se uma personalização SecurityTokenSerializer deve ser criada. Para obter mais informações sobre tokens de segurança personalizados e serializadores de token de segurança personalizados, consulte Como criar um token personalizado.

    internal class MyClientCredentialsSecurityTokenManager :
        ClientCredentialsSecurityTokenManager
    {
        MyClientCredentials credentials;
    
        public MyClientCredentialsSecurityTokenManager(MyClientCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenProvider CreateSecurityTokenProvider(
            SecurityTokenRequirement tokenRequirement)
        {
            // Return your implementation of the SecurityTokenProvider, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenProvider(tokenRequirement);
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(
            SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            // Return your implementation of the SecurityTokenAuthenticator, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
        }
    
        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
        {
            // Return your implementation of the SecurityTokenSerializer, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenSerializer(version);
        }
    }
    
    
    Friend Class MyClientCredentialsSecurityTokenManager
        Inherits ClientCredentialsSecurityTokenManager
        Private credentials As MyClientCredentials
    
    
        Public Sub New(ByVal credentials As MyClientCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
    
        End Sub
    
    
        Public Overrides Function CreateSecurityTokenProvider( _
        ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider
            ' Return your implementation of the SecurityTokenProvider, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenProvider(tokenRequirement)
    
        End Function
    
    
        Public Overrides Function CreateSecurityTokenAuthenticator( _
        ByVal tokenRequirement As SecurityTokenRequirement, _
        ByRef outOfBandTokenResolver As SecurityTokenResolver) As SecurityTokenAuthenticator
            ' Return your implementation of the SecurityTokenAuthenticator, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, outOfBandTokenResolver)
    
        End Function
    
    
        Public Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) _
        As SecurityTokenSerializer
            ' Return your implementation of the SecurityTokenSerializer, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenSerializer(version)
    
        End Function
    End Class
    

Para usar credenciais de cliente personalizadas do código do aplicativo

  1. Crie uma instância do cliente gerado que represente a interface de serviço ou crie uma instância do apontamento para um serviço com o ChannelFactory qual você deseja se comunicar.

  2. Remova o comportamento de credenciais de cliente fornecidas pelo sistema da coleção, que pode ser acessado Behaviors por meio da Endpoint propriedade.

  3. Crie uma nova instância de uma classe de credenciais de cliente personalizada e adicione-a Behaviors à coleção, que pode ser acessada por meio da Endpoint propriedade.

    // Create a client with the client endpoint configuration.
    CalculatorClient client = new CalculatorClient();
    
    // Remove the ClientCredentials behavior.
    client.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
    
    // Add a custom client credentials instance to the behaviors collection.
    client.ChannelFactory.Endpoint.Behaviors.Add(new MyClientCredentials());
    
    ' Create a client with the client endpoint configuration.
    Dim client As New CalculatorClient()
    
    ' Remove the ClientCredentials behavior.
    client.ChannelFactory.Endpoint.Behaviors.Remove(Of ClientCredentials)()
    
    ' Add a custom client credentials instance to the behaviors collection.
    client.ChannelFactory.Endpoint.Behaviors.Add(New MyClientCredentials())
    

O procedimento anterior mostra como usar credenciais de cliente do código do aplicativo. As credenciais WCF também podem ser configuradas usando o arquivo de configuração do aplicativo. O uso da configuração do aplicativo geralmente é preferível à codificação rígida porque permite a modificação dos parâmetros do aplicativo sem ter que modificar a origem, a recompilação e a reimplantação.

O próximo procedimento descreve como fornecer suporte para a configuração de credenciais personalizadas.

Criando um manipulador de configuração para credenciais de cliente personalizadas

  1. Defina uma nova classe derivada de ClientCredentialsElement.

  2. Opcional. Adicione propriedades para todos os parâmetros de configuração adicionais que você deseja expor por por meio da configuração do aplicativo. O exemplo abaixo adiciona uma propriedade chamada CreditCardNumber.

  3. Substitua a BehaviorType propriedade para retornar o tipo da classe de credenciais de cliente personalizada criada com o elemento de configuração.

  4. Substitua o CreateBehavior método. O método é responsável por criar e retornar uma instância da classe de credenciais personalizada com base nas configurações carregadas do arquivo de configuração. Chame o método base ApplyConfiguration(ClientCredentials) desse método para recuperar as configurações de credenciais fornecidas pelo sistema carregadas em sua instância de credenciais de cliente personalizada.

  5. Opcional. Se você adicionou propriedades adicionais na etapa 2, precisará substituir a Properties propriedade para registrar suas definições de configuração adicionais para que a estrutura de configuração as reconheça. Combine suas propriedades com as propriedades da classe base para permitir que as configurações fornecidas pelo sistema sejam configuradas por meio desse elemento de configuração de credenciais de cliente personalizado.

    public class MyClientCredentialsConfigHandler : ClientCredentialsElement
    {
        ConfigurationPropertyCollection properties;
    
        public override Type BehaviorType
        {
            get { return typeof(MyClientCredentials); }
        }
    
        public string CreditCardNumber
        {
            get { return (string)base["creditCardNumber"]; }
            set
            {
                if (String.IsNullOrEmpty(value))
                {
                    value = String.Empty;
                }
                base["creditCardNumber"] = value;
            }
        }
    
        protected override ConfigurationPropertyCollection Properties
        {
            get
            {
                if (this.properties == null)
                {
                    ConfigurationPropertyCollection properties = base.Properties;
                    properties.Add(new ConfigurationProperty(
                        "creditCardNumber",
                        typeof(System.String),
                        string.Empty,
                        null,
                        new StringValidator(0, 32, null),
                        ConfigurationPropertyOptions.None));
                    this.properties = properties;
                }
                return this.properties;
            }
        }
    
        protected override object CreateBehavior()
        {
            MyClientCredentials creds = new MyClientCredentials();
            creds.CreditCardNumber = CreditCardNumber;
            base.ApplyConfiguration(creds);
            return creds;
        }
    }
    
    
    Public Class MyClientCredentialsConfigHandler
        Inherits ClientCredentialsElement
        Private propertiesValue As ConfigurationPropertyCollection
    
    
        Public Overrides ReadOnly Property BehaviorType() As Type
            Get
                Return GetType(MyClientCredentials)
            End Get
        End Property
    
        Public Property CreditCardNumber() As String
            Get
                Return CStr(MyBase.Item("creditCardNumber"))
            End Get
            Set
                If String.IsNullOrEmpty(value) Then
                    value = String.Empty
                End If
                MyBase.Item("creditCardNumber") = value
            End Set
        End Property
    
    
        Protected Overrides ReadOnly Property Properties() As ConfigurationPropertyCollection
            Get
                If Me.propertiesValue Is Nothing Then
                    Dim myProperties As ConfigurationPropertyCollection = MyBase.Properties
                    myProperties.Add(New ConfigurationProperty( _
                    "creditCardNumber", _
                    GetType(System.String), _
                    String.Empty, _
                    Nothing, _
                    New StringValidator(0, 32, Nothing), _
                    ConfigurationPropertyOptions.None))
                    Me.propertiesValue = myProperties
                End If
                Return Me.propertiesValue
            End Get
        End Property
    
    
        Protected Overrides Function CreateBehavior() As Object
            Dim creds As New MyClientCredentials()
            creds.CreditCardNumber = Me.CreditCardNumber
            MyBase.ApplyConfiguration(creds)
            Return creds
    
        End Function
    End Class
    

Depois de ter a classe do manipulador de configuração, ela pode ser integrada à estrutura de configuração do WCF. Isso permite que as credenciais personalizadas do cliente sejam usadas nos elementos de comportamento do ponto de extremidade do cliente, conforme mostrado no próximo procedimento.

Para registrar e usar um manipulador de configuração de credenciais de cliente personalizado na configuração do aplicativo

  1. Adicione um <extensions> elemento e um <behaviorExtensions> elemento ao arquivo de configuração.

  2. Adicione um <add> elemento ao <behaviorExtensions> elemento e defina o name atributo como um valor apropriado.

  3. Defina o type atributo como o nome do tipo totalmente qualificado. Inclua também o nome do assembly e outros atributos do assembly.

    <system.serviceModel>
      <extensions>
        <behaviorExtensions>
          <add name="myClientCredentials" type="Microsoft.ServiceModel.Samples.MyClientCredentialsConfigHandler, CustomCredentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </behaviorExtensions>
      </extensions>
    </system.serviceModel>
    
  4. Depois de registrar seu manipulador de configuração, o elemento de credenciais personalizado pode ser usado dentro do mesmo arquivo de configuração em vez do elemento fornecido <clientCredentials> pelo sistema. Você pode usar as propriedades fornecidas pelo sistema e quaisquer novas propriedades adicionadas à implementação do manipulador de configuração. O exemplo a seguir define o valor de uma propriedade personalizada usando o creditCardNumber atributo.

    <behaviors>
      <endpointBehaviors>
        <behavior name="myClientCredentialsBehavior">
          <myClientCredentials creditCardNumber="123-123-123"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    

Para implementar credenciais de serviço personalizadas

  1. Defina uma nova classe derivada de ServiceCredentials.

  2. Opcional. Adicione novas propriedades para fornecer APIs para novos valores de credenciais que estão sendo adicionados. Se você não adicionar novos valores de credencial, ignore esta etapa. O exemplo a seguir adiciona uma AdditionalCertificate propriedade.

  3. Substitua o CreateSecurityTokenManager método. Esse método é chamado automaticamente pela infraestrutura WCF quando a credencial de cliente personalizada é usada. O método é responsável por criar e retornar uma instância de uma implementação da SecurityTokenManager classe (descrita no próximo procedimento).

  4. Opcional. Substitua o CloneCore método. Isso é necessário somente se adicionar novas propriedades ou campos internos à implementação de credenciais de cliente personalizadas.

    public class MyServiceCredentials : ServiceCredentials
    {
        X509Certificate2 additionalCertificate;
    
        public MyServiceCredentials()
        {
        }
    
        protected MyServiceCredentials(MyServiceCredentials other)
            : base(other)
        {
            this.additionalCertificate = other.additionalCertificate;
        }
    
        public X509Certificate2 AdditionalCertificate
        {
            get
            {
                return this.additionalCertificate;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                this.additionalCertificate = value;
            }
        }
    
        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return base.CreateSecurityTokenManager();
        }
    
        protected override ServiceCredentials CloneCore()
        {
            return new MyServiceCredentials(this);
        }
    }
    
    Public Class MyServiceCredentials
        Inherits ServiceCredentials
        Private additionalCertificateValue As X509Certificate2
    
        Public Sub New()
    
        End Sub
    
        Protected Sub New(ByVal other As MyServiceCredentials)
            MyBase.New(other)
            Me.additionalCertificate = other.additionalCertificate
        End Sub
    
    
        Public Property AdditionalCertificate() As X509Certificate2
            Get
                Return Me.additionalCertificateValue
            End Get
            Set
                If value Is Nothing Then
                    Throw New ArgumentNullException("value")
                End If
                Me.additionalCertificateValue = value
            End Set
        End Property
    
        Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager
            Return MyBase.CreateSecurityTokenManager()
    
        End Function
    
    
        Protected Overrides Function CloneCore() As ServiceCredentials
            Return New MyServiceCredentials(Me)
    
        End Function
    End Class
    

Para implementar um gerenciador de token de segurança de serviço personalizado

  1. Defina uma nova classe derivada da ServiceCredentialsSecurityTokenManager classe.

  2. Opcional. Substitua o CreateSecurityTokenProvider método se uma implementação personalizada SecurityTokenProvider deve ser criada. Para obter mais informações sobre provedores de token de segurança personalizados, consulte Como criar um provedor de token de segurança personalizado.

  3. Opcional. Substitua o CreateSecurityTokenAuthenticator método se uma implementação personalizada SecurityTokenAuthenticator deve ser criada. Para obter mais informações sobre autenticadores de token de segurança personalizados, consulte o tópico Como criar um autenticador de token de segurança personalizado.

  4. Opcional. Substitua o CreateSecurityTokenSerializer(SecurityTokenVersion) método se uma personalização SecurityTokenSerializer deve ser criada. Para obter mais informações sobre tokens de segurança personalizados e serializadores de token de segurança personalizados, consulte Como criar um token personalizado.

    internal class MyServiceCredentialsSecurityTokenManager :
        ServiceCredentialsSecurityTokenManager
    {
        MyServiceCredentials credentials;
    
        public MyServiceCredentialsSecurityTokenManager(MyServiceCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
        {
            // Return your implementation of SecurityTokenProvider, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenProvider(tokenRequirement);
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            // Return your implementation of SecurityTokenProvider, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
        }
    
        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
        {
            // Return your implementation of SecurityTokenProvider, if required.
            // This implementation delegates to the base class.
            return base.CreateSecurityTokenSerializer(version);
        }
    }
    
    Friend Class MyServiceCredentialsSecurityTokenManager
        Inherits ServiceCredentialsSecurityTokenManager
        Private credentials As MyServiceCredentials
    
        Public Sub New(ByVal credentials As MyServiceCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
    
        End Sub
    
    
        Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) _
        As SecurityTokenProvider
            ' Return your implementation of SecurityTokenProvider, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenProvider(tokenRequirement)
    
        End Function
    
        Public Overrides Function CreateSecurityTokenAuthenticator( _
        ByVal tokenRequirement As SecurityTokenRequirement, _
        ByRef outOfBandTokenResolver As SecurityTokenResolver) _
        As SecurityTokenAuthenticator
            ' Return your implementation of SecurityTokenProvider, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, outOfBandTokenResolver)
    
        End Function
    
    
        Public Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) _
        As SecurityTokenSerializer
            ' Return your implementation of SecurityTokenProvider, if required.
            ' This implementation delegates to the base class.
            Return MyBase.CreateSecurityTokenSerializer(version)
    
        End Function
    End Class
    

Para usar credenciais de serviço personalizadas do código do aplicativo

  1. Crie uma instância de ServiceHost.

  2. Remova o comportamento de credenciais de serviço fornecidas pelo sistema da Behaviors coleção.

  3. Crie uma nova instância da classe de credenciais de serviço personalizada e adicione-a Behaviors à coleção.

    // Create a service host with a service type.
    ServiceHost serviceHost = new ServiceHost(typeof(Service));
    
    // Remove the default ServiceCredentials behavior.
    serviceHost.Description.Behaviors.Remove<ServiceCredentials>();
    
    // Add a custom service credentials instance to the collection.
    serviceHost.Description.Behaviors.Add(new MyServiceCredentials());
    
    ' Create a service host with a service type.
    Dim serviceHost As New ServiceHost(GetType(Service))
    
    ' Remove the default ServiceCredentials behavior.
    serviceHost.Description.Behaviors.Remove(Of ServiceCredentials)()
    
    ' Add a custom service credentials instance to the collection.
    serviceHost.Description.Behaviors.Add(New MyServiceCredentials())
    

Adicione suporte para configuração usando as etapas descritas anteriormente nos procedimentos "To create a configuration handler for custom client credentials" e "To register and use a custom client credentials configuration handler in the application configuration." A única diferença é usar a ServiceCredentialsElement classe em vez da classe como uma classe base para o manipulador de ClientCredentialsElement configuração. O elemento de credencial de serviço personalizado pode ser usado sempre que o elemento fornecido <serviceCredentials> pelo sistema for usado.

Consulte também