Partilhar via


Como: criar um autenticador personalizado de token de segurança

Este tópico mostra como criar um autenticador personalizado de tokens de segurança e como integrá-lo com um gestor personalizado de tokens de segurança. Um autenticador de token de segurança valida o conteúdo de um token de segurança fornecido com uma mensagem recebida. Se a validação for bem-sucedida, o autenticador devolve uma coleção de IAuthorizationPolicy instâncias que, quando avaliadas, devolve um conjunto de reivindicações.

Para usar um autenticador de token de segurança personalizado no Windows Communication Foundation (WCF), deve primeiro criar credenciais personalizadas e implementações de gestor de tokens de segurança. Para mais informações sobre a criação de credenciais personalizadas e um gestor de tokens de segurança, consulte Guia: Criação de Credenciais Personalizadas para Clientes e Serviços.

Procedimentos

Para criar um autenticador personalizado de token de segurança

  1. Defina uma nova classe derivada da SecurityTokenAuthenticator classe.

  2. Sobreponha o método CanValidateTokenCore. O método retorna true ou false depende se o autenticador personalizado consegue validar o tipo de token recebido ou não.

  3. Sobreponha o método ValidateTokenCore. Este método precisa de validar adequadamente o conteúdo dos tokens. Se o token passar a etapa de validação, devolve uma coleção de IAuthorizationPolicy instâncias. O exemplo seguinte utiliza uma implementação de política de autorização personalizada que será criada no procedimento seguinte.

    internal class MySecurityTokenAuthenticator : SecurityTokenAuthenticator
    {
        protected override bool CanValidateTokenCore(SecurityToken token)
        {
            // Check that the incoming token is a username token type that
            // can be validated by this implementation.
            return (token is UserNameSecurityToken);
        }
    
        protected override ReadOnlyCollection<IAuthorizationPolicy>
            ValidateTokenCore(SecurityToken token)
        {
            UserNameSecurityToken userNameToken = token as UserNameSecurityToken;
    
            // Validate the information contained in the username token. For demonstration
            // purposes, this code just checks that the user name matches the password.
            if (userNameToken.UserName != userNameToken.Password)
            {
                throw new SecurityTokenValidationException("Invalid user name or password");
            }
    
            // Create just one Claim instance for the username token - the name of the user.
            DefaultClaimSet userNameClaimSet = new DefaultClaimSet(
                ClaimSet.System,
                new Claim(ClaimTypes.Name, userNameToken.UserName, Rights.PossessProperty));
            List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
            policies.Add(new MyAuthorizationPolicy(userNameClaimSet));
            return policies.AsReadOnly();
        }
    }
    
    Friend Class MySecurityTokenAuthenticator
        Inherits SecurityTokenAuthenticator
    
        Protected Overrides Function CanValidateTokenCore(ByVal token As SecurityToken) As Boolean
            ' Check that the incoming token is a username token type that  
            ' can be validated by this implementation.
            Return (TypeOf token Is UserNameSecurityToken)
        End Function
    
        Protected Overrides Function ValidateTokenCore(ByVal token As SecurityToken) As ReadOnlyCollection(Of IAuthorizationPolicy)
    
            Dim userNameToken = TryCast(token, UserNameSecurityToken)
    
            ' Validate the information contained in the username token. For demonstration 
            ' purposes, this code just checks that the user name matches the password.
            If userNameToken.UserName <> userNameToken.Password Then
                Throw New SecurityTokenValidationException("Invalid user name or password")
            End If
    
            ' Create just one Claim instance for the username token - the name of the user.
            Dim userNameClaimSet As New DefaultClaimSet(ClaimSet.System, _
                                                        New Claim(ClaimTypes.Name, _
                                                        userNameToken.UserName, _
                                                        Rights.PossessProperty))
            Dim policies As New List(Of IAuthorizationPolicy)(1)
            policies.Add(New MyAuthorizationPolicy(userNameClaimSet))
            Return policies.AsReadOnly()
        End Function
    
    End Class
    

O código anterior devolve uma coleção de políticas de autorização no CanValidateToken(SecurityToken) método. O WCF não fornece uma implementação pública desta interface. O procedimento seguinte mostra como o fazer para as suas próprias necessidades.

Para criar uma política de autorização personalizada

  1. Defina uma nova classe a implementar a IAuthorizationPolicy interface.

  2. Implemente a Id propriedade de apenas leitura. Uma forma de implementar esta propriedade é gerar um identificador globalmente único (GUID) no construtor de classes e devolvê-lo sempre que o valor desta propriedade for solicitado.

  3. Implemente a Issuer propriedade de apenas leitura. Esta propriedade deve devolver um emissor dos conjuntos de reivindicações obtidos do token. Este emissor deve corresponder ao emissor do token ou a uma autoridade responsável por validar o conteúdo do token. O exemplo seguinte utiliza a declaração do emissor que foi passada para esta classe a partir do autenticador personalizado de token de segurança criado no procedimento anterior. O autenticador de token de segurança personalizado utiliza o conjunto de reivindicações fornecido pelo sistema (devolvido pela System propriedade) para representar o emissor do token de nome de utilizador.

  4. Implemente o método Evaluate. Este método preenche uma instância da EvaluationContext classe (passada como argumento) com reivindicações baseadas no conteúdo do token de segurança recebido. O método regressa true quando termina a avaliação. Nos casos em que a implementação depende da presença de outras políticas de autorização que forneçam informação adicional ao contexto de avaliação, este método pode regressar false se a informação necessária ainda não estiver presente no contexto da avaliação. Nesse caso, o WCF voltará a chamar o método após avaliar todas as outras políticas de autorização geradas para a mensagem recebida, caso pelo menos uma dessas políticas tenha modificado o contexto de avaliação.

    internal class MyAuthorizationPolicy : IAuthorizationPolicy
    {
        string id;
        ClaimSet tokenClaims;
        ClaimSet issuer;
    
        public MyAuthorizationPolicy(ClaimSet tokenClaims)
        {
            if (tokenClaims == null)
            {
                throw new ArgumentNullException("tokenClaims");
            }
            this.issuer = tokenClaims.Issuer;
            this.tokenClaims = tokenClaims;
            this.id = Guid.NewGuid().ToString();
        }
    
        public ClaimSet Issuer
        {
            get { return issuer; }
        }
    
        public string Id
        {
            get { return id; }
        }
    
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            // Add the token claim set to the evaluation context.
            evaluationContext.AddClaimSet(this, tokenClaims);
    
            // Return true if the policy evaluation is finished.
            return true;
        }
    }
    
    Friend Class MyAuthorizationPolicy
        Implements IAuthorizationPolicy
    
        Private _id As String
        Private _tokenClaims As ClaimSet
        Private _issuer As ClaimSet
    
        Public Sub New(ByVal tokenClaims As ClaimSet)
            If _tokenClaims Is Nothing Then
                Throw New ArgumentNullException("tokenClaims")
            End If
            Me._issuer = tokenClaims.Issuer
            Me._tokenClaims = tokenClaims
            Me._id = Guid.NewGuid().ToString()
        End Sub
    
        Public ReadOnly Property Issuer() As ClaimSet Implements IAuthorizationPolicy.Issuer
            Get
                Return _issuer
            End Get
        End Property
    
        Public ReadOnly Property Id() As String Implements System.IdentityModel.Policy.IAuthorizationComponent.Id
            Get
                Return _id
            End Get
        End Property
    
        Public Function Evaluate(ByVal evaluationContext As EvaluationContext, _
                                 ByRef state As Object) As Boolean Implements IAuthorizationPolicy.Evaluate
    
            ' Add the token claim set to the evaluation context.
            evaluationContext.AddClaimSet(Me, _tokenClaims)
            ' Return true if the policy evaluation is finished.
            Return True
        End Function
    
    End Class
    

Guia: Criar Credenciais Personalizadas para Clientes e Serviços descreve como criar credenciais personalizadas e um gestor personalizado de tokens de segurança. Para usar o autenticador personalizado de tokens de segurança criado aqui, uma implementação do gestor de tokens de segurança é modificada para devolver o autenticador personalizado do CreateSecurityTokenAuthenticator método. O método devolve um autenticador quando é passado um requisito de token de segurança apropriado.

Para integrar um autenticador de token de segurança personalizado com um gestor de token de segurança personalizado

  1. Substitua o método CreateSecurityTokenAuthenticator na sua implementação personalizada do gerenciador de tokens de segurança.

  2. Adicione lógica ao método para permitir que este devolva o seu autenticador personalizado de token de segurança com base no SecurityTokenRequirement parâmetro. O exemplo seguinte devolve um autenticador personalizado de token de segurança se o tipo de token de requisitos do token for um nome de utilizador (representado pela UserName propriedade) e a direção da mensagem para a qual o autenticador de token de segurança está a ser solicitado for introduzida (representada pelo Input campo).

    internal class MyServiceCredentialsSecurityTokenManager :
        ServiceCredentialsSecurityTokenManager
    {
        ServiceCredentials credentials;
        public MyServiceCredentialsSecurityTokenManager(ServiceCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator
            (SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            // Return your implementation of the SecurityTokenProvider based on the
            // tokenRequirement argument.
            SecurityTokenAuthenticator result;
            if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)
            {
                MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>
                    (ServiceModelSecurityTokenRequirement.MessageDirectionProperty);
                if (direction == MessageDirection.Input)
                {
                    outOfBandTokenResolver = null;
                    result = new MySecurityTokenAuthenticator();
                }
                else
                {
                    result = base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
                }
            }
            else
            {
                result = base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
            }
    
            return result;
        }
    }
    
    Friend Class MyServiceCredentialsSecurityTokenManager
        Inherits ServiceCredentialsSecurityTokenManager
    
        Private credentials As ServiceCredentials
    
        Public Sub New(ByVal credentials As ServiceCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
        End Sub
    
        Public Overrides Function CreateSecurityTokenAuthenticator(ByVal tokenRequirement As SecurityTokenRequirement, _
                                                                   <System.Runtime.InteropServices.Out()> _
                                                                   ByRef outOfBandTokenResolver _
                                                                   As SecurityTokenResolver) As SecurityTokenAuthenticator
            ' Return your implementation of the SecurityTokenProvider based on the 
            ' tokenRequirement argument.
            Dim result As SecurityTokenAuthenticator
            If tokenRequirement.TokenType = SecurityTokenTypes.UserName Then
                Dim direction = tokenRequirement.GetProperty(Of MessageDirection)(ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
                If direction = MessageDirection.Input Then
                    outOfBandTokenResolver = Nothing
                    result = New MySecurityTokenAuthenticator()
                Else
                    result = MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, _
                                                                     outOfBandTokenResolver)
                End If
            Else
                result = MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, _
                                                                 outOfBandTokenResolver)
            End If
    
            Return result
        End Function
    
    End Class
    

Consulte também