Como: usar um validador personalizado de nome de usuário e senha

Por padrão, quando um nome de usuário e uma senha são usados para autenticação, o WCF (Windows Communication Foundation) usa o Windows para validar esses dados. No entanto, o WCF permite esquemas personalizados de autenticação de nome de usuário e senha, também conhecido como validadores. Para inserir um validador personalizado de nome de usuário e senha, crie uma classe que deriva de UserNamePasswordValidator e configure-a.

Para obter um aplicativo de exemplo, consulte o Validador de Nome de Usuário e Senha.

Para criar um validador personalizado de nome de usuário e senha

  1. Crie uma classe que deriva de UserNamePasswordValidator.

    
    public class CustomUserNameValidator : UserNamePasswordValidator
    {
    
    Public Class CustomUserNameValidator
        Inherits UserNamePasswordValidator
    
  2. Implemente o esquema de autenticação personalizado substituindo o método Validate.

    Não use o código no exemplo a seguir que substitui o método Validate em um ambiente de produção. Substitua o código pelo esquema personalizado de validação de nome de usuário e senha, o que pode envolver recuperar pares de nome de usuário e senha de um banco de dados.

    Para retornar erros de autenticação de volta para o cliente, gere um FaultException no método Validate.

    // This method validates users. It allows in two users, test1 and test2
    // with passwords 1tset and 2tset respectively.
    // This code is for illustration purposes only and
    // must not be used in a production environment because it is not secure.
    public override void Validate(string userName, string password)
    {
        if (null == userName || null == password)
        {
            throw new ArgumentNullException();
        }
    
        if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
        {
            // This throws an informative fault to the client.
            throw new FaultException("Unknown Username or Incorrect Password");
            // When you do not want to throw an informative fault to the client,
            // throw the following exception.
            // throw new SecurityTokenException("Unknown Username or Incorrect Password");
        }
    }
    
    ' This method validates users. It allows in two users, test1 and test2
    ' with passwords 1tset and 2tset respectively.
    ' This code is for illustration purposes only and
    ' must not be used in a production environment because it is not secure.
    Public Overrides Sub Validate(ByVal userName As String, ByVal password As String)
        If Nothing = userName OrElse Nothing = password Then
            Throw New ArgumentNullException()
        End If
    
        If Not (userName = "test1" AndAlso password = "[PLACEHOLDER]") AndAlso Not (userName = "test2" AndAlso password = "[PLACEHOLDER]") Then
            ' This throws an informative fault to the client.
            Throw New FaultException("Unknown Username or Incorrect Password")
            ' When you do not want to throw an informative fault to the client,
            ' throw the following exception:
            ' Throw New SecurityTokenException("Unknown Username or Incorrect Password")
        End If
    
    End Sub
    

Para configurar um serviço para usar um validador personalizado de nome de usuário e senha

  1. Configure uma associação que usa segurança de mensagem sobre qualquer transporte ou segurança em nível de transporte sobre HTTP.

    Ao usar a segurança de mensagem, adicione uma das associações fornecidas pelo sistema, como uma <wsHttpBinding> ou uma <customBinding> que dá suporte à segurança de mensagem e o tipo de credencial UserName.

    Ao usar a segurança em nível de transporte sobre HTTP(S), adicione o <wsHttpBinding> ou <basicHttpBinding>, um <netTcpBinding> ou um <customBinding> que use HTTP(S) e o esquema de autenticação Basic.

    Observação

    Ao usar o .NET Framework 3.5 ou versões posteriores, você pode usar um validador personalizado de nome de usuário e senha com a segurança de mensagem e transporte. Com o WinFX, um validador personalizado de nome de usuário e senha só pode ser usado com segurança de mensagem.

    Dica

    Para obter mais informações sobre como usar <netTcpBinding> neste contexto, consulte <Segurança>.

    1. No arquivo de configuração, no elemento <system.serviceModel>, adicione um elemento <bindings>.

    2. Adicione um elemento <wsHttpBinding> ou <basicHttpBinding> à seção bindings. Para obter mais informações sobre como criar um elemento de associação WCF, consulte Como especificar uma associação de serviço na configuração.

    3. Defina o atributo mode de <security> ou <security> como Message, Transport ou TransportWithMessageCredential.

    4. Defina o atributo clientCredentialType de <message> ou <transport>.

      Ao usar a segurança de mensagem, defina o atributo clientCredentialType de <message> como UserName.

      Ao usar a segurança em nível de transporte sobre HTTP(S), defina o atributo clientCredentialType de <transport> ou <transport> como Basic.

      Observação

      Quando um serviço do WCF está hospedado nos Serviços de Informações da Internet (IIS) usando a segurança em nível de transporte e a propriedade UserNamePasswordValidationMode está definida como Custom, o esquema de autenticação personalizada usa um subconjunto de autenticação do Windows. Isso ocorre porque, neste cenário, o IIS efetua a autenticação do Windows antes de o WCF chamar o autenticador personalizado.

    Para obter mais informações sobre como criar um elemento de associação WCF, consulte Como especificar uma associação de serviço na configuração.

    O exemplo a seguir mostra o código de configuração para a associação:

    <system.serviceModel>
      <bindings>
      <wsHttpBinding>
          <binding name="Binding1">
            <security mode="Message">
              <message clientCredentialType="UserName" />
            </security>
          </binding>
        </wsHttpBinding>
      </bindings>
    </system.serviceModel>
    
  2. Configure um comportamento que especifica que um validador personalizado de nome de usuário e senha é usado para validar os pares de nome de usuário e senha para tokens de segurança de entrada do UserNameSecurityToken.

    1. Como um filho do elemento <system.serviceModel>, adicione um elemento <behaviours>.

    2. Adicione um <serviceBehaviors> ao elemento <behaviors>.

    3. Adicione um elemento <behavior> e defina o atributo name com um valor apropriado.

    4. Adicione um <serviceCredentials> ao elemento <behavior>.

    5. Adicione um <userNameAuthentication> ao <serviceCredentials>.

    6. Defina o userNamePasswordValidationMode para Custom.

      Importante

      Se o valor de userNamePasswordValidationMode não estiver definido, o WCF usará a autenticação do Windows em vez do validador personalizado de nome de usuário e senha.

    7. Defina customUserNamePasswordValidatorType como o tipo que representa o seu validador personalizado de nome de usuário e senha.

    O exemplo a seguir mostra o fragmento do <serviceCredentials> até este ponto:

    <serviceCredentials>
      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.CalculatorService.CustomUserNameValidator, service" />
    </serviceCredentials>
    

Exemplo

O exemplo de código a seguir demonstra como criar um validador personalizado de nome de usuário e senha. Não use o código que substitui o método Validate em um ambiente de produção. Substitua o código pelo esquema personalizado de validação de nome de usuário e senha, o que pode envolver recuperar pares de nome de usuário e senha de um banco de dados.

using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;

using System.Security.Principal;

using System.ServiceModel;
Imports System.IdentityModel.Selectors
Imports System.IdentityModel.Tokens

Imports System.Security.Principal

Imports System.ServiceModel

public class CustomUserNameValidator : UserNamePasswordValidator
{
    // This method validates users. It allows in two users, test1 and test2
    // with passwords 1tset and 2tset respectively.
    // This code is for illustration purposes only and
    // must not be used in a production environment because it is not secure.
    public override void Validate(string userName, string password)
    {
        if (null == userName || null == password)
        {
            throw new ArgumentNullException();
        }

        if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
        {
            // This throws an informative fault to the client.
            throw new FaultException("Unknown Username or Incorrect Password");
            // When you do not want to throw an informative fault to the client,
            // throw the following exception.
            // throw new SecurityTokenException("Unknown Username or Incorrect Password");
        }
    }
}
Public Class CustomUserNameValidator
    Inherits UserNamePasswordValidator
    ' This method validates users. It allows in two users, test1 and test2
    ' with passwords 1tset and 2tset respectively.
    ' This code is for illustration purposes only and
    ' must not be used in a production environment because it is not secure.
    Public Overrides Sub Validate(ByVal userName As String, ByVal password As String)
        If Nothing = userName OrElse Nothing = password Then
            Throw New ArgumentNullException()
        End If

        If Not (userName = "test1" AndAlso password = "[PLACEHOLDER]") AndAlso Not (userName = "test2" AndAlso password = "[PLACEHOLDER]") Then
            ' This throws an informative fault to the client.
            Throw New FaultException("Unknown Username or Incorrect Password")
            ' When you do not want to throw an informative fault to the client,
            ' throw the following exception:
            ' Throw New SecurityTokenException("Unknown Username or Incorrect Password")
        End If

    End Sub
End Class

Confira também