Freigeben über


Anleitung: Erstellen eines benutzerdefinierten Client-Identitätsprüfers

Mit dem Identitätsfeature von Windows Communication Foundation (WCF) kann ein Client im Voraus die erwartete Identität des Diensts angeben. Wenn sich ein Server beim Client authentifiziert, wird die Identität anhand der erwarteten Identität überprüft. (Eine Erläuterung der Identität und ihrer Funktionsweise finden Sie unter Dienstidentität und Authentifizierung.)

Bei Bedarf kann die Überprüfung mithilfe einer benutzerdefinierten Identitätsprüfung angepasst werden. Sie können z. B. zusätzliche Überprüfungen der Dienstidentität durchführen. In diesem Beispiel überprüft die benutzerdefinierte Identitätsprüfung zusätzliche Ansprüche im vom Server zurückgegebenen X.509-Zertifikat. Eine Beispielanwendung finden Sie unter Service Identity Sample.

So erweitern Sie die EndpointIdentity-Klasse

  1. Definieren Sie eine neue Klasse, die von der EndpointIdentity Klasse abgeleitet wird. In diesem Beispiel wird die Erweiterung OrgEndpointIdentitybenannt.

  2. Fügen Sie private Mitglieder und Eigenschaften hinzu, die von der erweiterten IdentityVerifier Klasse verwendet werden, um die Identitätsprüfung für Ansprüche im Sicherheitstoken durchzuführen, das vom Dienst zurückgegeben wird. In diesem Beispiel wird eine Eigenschaft definiert: die OrganizationClaim Eigenschaft.

    public class OrgEndpointIdentity : EndpointIdentity
    {
        private string orgClaim;
        public OrgEndpointIdentity(string orgName)
        {
            orgClaim = orgName;
        }
    
        public string OrganizationClaim
        {
            get { return orgClaim; }
            set { orgClaim = value; }
        }
    }
    
    Public Class OrgEndpointIdentity
        Inherits EndpointIdentity
        Private orgClaim As String
    
        Public Sub New(ByVal orgName As String)
            orgClaim = orgName
        End Sub
    
        Public Property OrganizationClaim() As String
            Get
                Return orgClaim
            End Get
            Set(ByVal value As String)
                orgClaim = value
            End Set
        End Property
    End Class
    

So erweitern Sie die IdentityVerifier-Klasse

  1. Definieren Sie eine neue Klasse, die von IdentityVerifier. In diesem Beispiel wird die Erweiterung CustomIdentityVerifierbenannt.

    public class CustomIdentityVerifier : IdentityVerifier
    {
        // Code to be added.
        public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
    
    Public Class CustomIdentityVerifier
        Inherits IdentityVerifier
        ' Code to be added.
    
        Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _
                                              ByVal authContext As AuthorizationContext) As Boolean
            Throw New Exception("The method or operation is not implemented.")
        End Function
    
        Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _
                                                 <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean
            Throw New Exception("The method or operation is not implemented.")
        End Function
    End Class
    
  2. Überschreiben Sie die CheckAccess Methode. Die Methode bestimmt, ob die Identitätsprüfung erfolgreich war oder fehlgeschlagen ist.

  3. Die CheckAccess Methode hat zwei Parameter. Der erste ist eine Instanz der EndpointIdentity Klasse. Die zweite ist eine Instanz der AuthorizationContext Klasse.

    Untersuchen Sie in der Methodenimplementierung die Sammlung von Ansprüchen, die von der ClaimSets Eigenschaft der AuthorizationContext Klasse zurückgegeben werden, und führen Sie Authentifizierungsprüfungen nach Bedarf aus. Dieses Beispiel beginnt mit dem Suchen eines Anspruchs vom Typ "Distinguished Name" und vergleicht dann den Namen mit der Erweiterung der EndpointIdentity (OrgEndpointIdentity).

    public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
    {
        bool returnvalue = false;
    
        foreach (ClaimSet claimset in authContext.ClaimSets)
        {
            foreach (Claim claim in claimset)
            {
                if (claim.ClaimType == "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname")
                {
                    X500DistinguishedName name = (X500DistinguishedName)claim.Resource;
                    if (name.Name.Contains(((OrgEndpointIdentity)identity).OrganizationClaim))
                    {
                        Console.WriteLine($"Claim Type: {claim.ClaimType}");
                        Console.WriteLine($"Right: {claim.Right}");
                        Console.WriteLine($"Resource: {claim.Resource}");
                        Console.WriteLine();
                        returnvalue = true;
                    }
                }
            }
        }
        return returnvalue;
    }
    
    
    Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _
                                          ByVal authContext As AuthorizationContext) As Boolean
    
        Dim returnvalue = False
        For Each claimset In authContext.ClaimSets
            For Each claim In claimset
                If claim.ClaimType = "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname" Then
                    Dim name = CType(claim.Resource, X500DistinguishedName)
                    If name.Name.Contains((CType(identity, OrgEndpointIdentity)).OrganizationClaim) Then
                        Console.WriteLine("Claim Type: {0}", claim.ClaimType)
                        Console.WriteLine("Right: {0}", claim.Right)
                        Console.WriteLine("Resource: {0}", claim.Resource)
                        Console.WriteLine()
                        returnvalue = True
                    End If
                End If
            Next claim
        Next claimset
        Return returnvalue
    
    End Function
    

So implementieren Sie die TryGetIdentity-Methode

  1. Implementieren Sie die TryGetIdentity Methode, die bestimmt, ob eine Instanz der EndpointIdentity Klasse vom Client zurückgegeben werden kann. Die WCF-Infrastruktur ruft zuerst die Implementierung der TryGetIdentity Methode auf, um die Identität des Diensts aus der Nachricht abzurufen. Als Nächstes ruft die Infrastruktur die Implementierung von CheckAccess mit der zurückgegebenen EndpointIdentity und AuthorizationContext auf.

  2. Fügen Sie in der TryGetIdentity Methode den folgenden Code ein:

    public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
    {
        return IdentityVerifier.CreateDefault().TryGetIdentity(reference, out identity);
    }
    
    Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _
                                             <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean
        Return IdentityVerifier.CreateDefault().TryGetIdentity(reference, identity)
    End Function
    
    

So implementieren Sie eine benutzerdefinierte Bindung und legen den benutzerdefinierten IdentityVerifier fest

  1. Erstellen Sie eine Methode, die ein Binding Objekt zurückgibt. In diesem Beispiel wird eine Instanz der WSHttpBinding Klasse erstellt, der Sicherheitsmodus auf Message gesetzt und ClientCredentialType auf None eingestellt.

  2. Erstellen Sie eine BindingElementCollection mithilfe der CreateBindingElements Methode.

  3. Geben Sie das SecurityBindingElement aus der Sammlung zurück und konvertieren es in eine SymmetricSecurityBindingElement-Variable.

  4. Legen Sie die IdentityVerifier Eigenschaft der LocalClientSecuritySettings Klasse auf eine neue Instanz der CustomIdentityVerifier zuvor erstellten Klasse fest.

    public static Binding CreateCustomSecurityBinding()
    {
        WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message);
        //Clients are anonymous to the service.
        binding.Security.Message.ClientCredentialType = MessageCredentialType.None;
        //Secure conversation is turned off for simplification. If secure conversation is turned on, then
        //you also need to set the IdentityVerifier on the secureconversation bootstrap binding.
        binding.Security.Message.EstablishSecurityContext = false;
    
        // Get the SecurityBindingElement and cast to a SymmetricSecurityBindingElement to set the IdentityVerifier.
        BindingElementCollection outputBec = binding.CreateBindingElements();
        SymmetricSecurityBindingElement ssbe = (SymmetricSecurityBindingElement)outputBec.Find<SecurityBindingElement>();
    
        //Set the Custom IdentityVerifier.
        ssbe.LocalClientSettings.IdentityVerifier = new CustomIdentityVerifier();
    
        return new CustomBinding(outputBec);
    }
    
    Public Shared Function CreateCustomSecurityBinding() As Binding
        Dim binding As New WSHttpBinding(SecurityMode.Message)
    
        With binding.Security.Message
            'Clients are anonymous to the service.
            .ClientCredentialType = MessageCredentialType.None
            'Secure conversation is turned off for simplification. If secure conversation is turned on, then 
            'you also need to set the IdentityVerifier on the secureconversation bootstrap binding.
            .EstablishSecurityContext = False
        End With
        ' Get the SecurityBindingElement and cast to a SymmetricSecurityBindingElement to set the IdentityVerifier.
        Dim outputBec = binding.CreateBindingElements()
        Dim ssbe = CType(outputBec.Find(Of SecurityBindingElement)(), SymmetricSecurityBindingElement)
    
        'Set the Custom IdentityVerifier.
        ssbe.LocalClientSettings.IdentityVerifier = New CustomIdentityVerifier()
    
        Return New CustomBinding(outputBec)
    End Function
    
  5. Die zurückgegebene benutzerdefinierte Bindung wird verwendet, um eine Instanz des Clients und der Klasse zu erstellen. Der Client kann dann eine benutzerdefinierte Identitätsüberprüfung des Diensts ausführen, wie im folgenden Code dargestellt.

    using (CalculatorClient client = new CalculatorClient(customSecurityBinding, serviceAddress))
    {
    
    Using client As New CalculatorClient(customSecurityBinding, serviceAddress)
    

Beispiel 1

Das folgende Beispiel zeigt eine vollständige Implementierung der IdentityVerifier Klasse.

class CustomIdentityVerifier : IdentityVerifier
{
    public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
    {
        bool returnvalue = false;

        foreach (ClaimSet claimset in authContext.ClaimSets)
        {
            foreach (Claim claim in claimset)
            {
                if (claim.ClaimType == "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname")
                {
                    X500DistinguishedName name = (X500DistinguishedName)claim.Resource;
                    if (name.Name.Contains(((OrgEndpointIdentity)identity).OrganizationClaim))
                    {
                        Console.WriteLine($"Claim Type: {claim.ClaimType}");
                        Console.WriteLine($"Right: {claim.Right}");
                        Console.WriteLine($"Resource: {claim.Resource}");
                        Console.WriteLine();
                        returnvalue = true;
                    }
                }
            }
        }
        return returnvalue;
    }

    public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
    {
        return IdentityVerifier.CreateDefault().TryGetIdentity(reference, out identity);
    }
}
Friend Class CustomIdentityVerifier
    Inherits IdentityVerifier

    Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _
                                          ByVal authContext As AuthorizationContext) As Boolean

        Dim returnvalue = False
        For Each claimset In authContext.ClaimSets
            For Each claim In claimset
                If claim.ClaimType = "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname" Then
                    Dim name = CType(claim.Resource, X500DistinguishedName)
                    If name.Name.Contains((CType(identity, OrgEndpointIdentity)).OrganizationClaim) Then
                        Console.WriteLine("Claim Type: {0}", claim.ClaimType)
                        Console.WriteLine("Right: {0}", claim.Right)
                        Console.WriteLine("Resource: {0}", claim.Resource)
                        Console.WriteLine()
                        returnvalue = True
                    End If
                End If
            Next claim
        Next claimset
        Return returnvalue

    End Function

    Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _
                                             <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean
        Return IdentityVerifier.CreateDefault().TryGetIdentity(reference, identity)
    End Function

End Class

Beispiel 2

Das folgende Beispiel zeigt eine vollständige Implementierung der EndpointIdentity Klasse.

public class OrgEndpointIdentity : EndpointIdentity
{
    private string orgClaim;
    public OrgEndpointIdentity(string orgName)
    {
        orgClaim = orgName;
    }

    public string OrganizationClaim
    {
        get { return orgClaim; }
        set { orgClaim = value; }
    }
}
Public Class OrgEndpointIdentity
    Inherits EndpointIdentity
    Private orgClaim As String

    Public Sub New(ByVal orgName As String)
        orgClaim = orgName
    End Sub

    Public Property OrganizationClaim() As String
        Get
            Return orgClaim
        End Get
        Set(ByVal value As String)
            orgClaim = value
        End Set
    End Property
End Class

Siehe auch