다음을 통해 공유


방법: 사용자 지정 클라이언트 ID 검증 도구 만들기

클라이언트는 WCF(Windows Communication Foundation)의 ID 기능을 사용하여 서비스에 필요한 ID를 미리 지정할 수 있습니다. 서버가 클라이언트에 자신을 인증할 때마다 이 ID와 비교하여 ID가 검사됩니다. ID와 ID의 작동 방식에 대한 자세한 내용은 서비스 ID 및 인증을 참조하십시오.

필요한 경우 사용자 지정 ID 검증 도구를 사용하여 확인을 사용자 지정할 수 있습니다. 예를 들어, 서비스 ID 확인 검사를 추가로 수행할 수 있습니다. 이 예에서 사용자 지정 ID 검증 도구는 서버에서 반환되는 X.509 인증서에서 추가 클레임을 검사합니다. 샘플 응용 프로그램을 보려면 Service Identity 샘플을 참조하십시오.

EndpointIdentity 클래스를 확장하려면

  1. EndpointIdentity 클래스에서 파생되는 새 클래스를 정의합니다. 이 예에서는 확장 이름을 OrgEndpointIdentity로 지정합니다.

  2. 서비스에서 반환된 보안 토큰의 클레임에 대해 ID 검사를 수행하기 위해 확장 IdentityVerifier 클래스에서 사용할 속성과 함께 private 멤버를 추가합니다. 이 예에서는 OrganizationClaim 속성 하나를 정의합니다.

    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
    
    public class OrgEndpointIdentity : EndpointIdentity
    {
        private string orgClaim;
        public OrgEndpointIdentity(string orgName)
        {
            orgClaim = orgName;
        }
    
        public string OrganizationClaim
        {
            get { return orgClaim; }
            set { orgClaim = value; }
        }
    }
    

IdentityVerifier 클래스를 확장하려면

  1. IdentityVerifier에서 파생되는 새 클래스를 정의합니다. 이 예에서는 확장 이름을 CustomIdentityVerifier로 지정합니다.

    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
    
    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.");
        }
    }
    
  2. CheckAccess 메서드를 재정의합니다. 이 메서드는 ID 검사의 성공 또는 실패 여부를 확인합니다.

  3. CheckAccess 메서드는 두 개의 매개 변수를 사용합니다. 하나는 EndpointIdentity 클래스의 인스턴스이고 다른 하나는 AuthorizationContext 클래스의 인스턴스입니다.

    메서드 구현에서는 AuthorizationContext 클래스의 ClaimSets 속성에서 반환된 클레임의 컬렉션을 검사한 다음 필요한 경우 인증 검사를 수행합니다. 이 예에서는 먼저 형식이 "고유 이름"인 클레임을 찾은 다음 EndpointIdentity의 확장(OrgEndpointIdentity)과 이름을 비교합니다.

    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 = "https://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 override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
    {
        bool returnvalue = false;
    
        foreach (ClaimSet claimset in authContext.ClaimSets)
        {
            foreach (Claim claim in claimset)
            {
                if (claim.ClaimType == "https://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: {0}", claim.ClaimType);
                        Console.WriteLine("Right: {0}", claim.Right);
                        Console.WriteLine("Resource: {0}", claim.Resource);
                        Console.WriteLine();
                        returnvalue = true;
                    }
                }
            }
    
        }
        return returnvalue;
    }
    

TryGetIdentity 메서드를 구현하려면

  1. 클라이언트가 EndpointIdentity 클래스의 인스턴스를 반환할 수 있는지 여부를 확인하는 TryGetIdentity 메서드를 구현합니다. WCF 인프라는 먼저 메시지에서 서비스의 ID를 가져오기 위해 TryGetIdentity 메서드의 구현을 호출합니다. 그런 다음 반환된 EndpointIdentityAuthorizationContext와 함께 CheckAccess 구현을 호출합니다.

  2. TryGetIdentity 메서드에서 다음 코드를 입력합니다.

    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
    
    public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
    {
        return IdentityVerifier.CreateDefault().TryGetIdentity(reference, out identity);
    }
    

사용자 지정 바인딩을 구현하고 사용자 지정 IdentityVerifier를 설정하려면

  1. Binding 개체를 반환하는 메서드를 만듭니다. 이 예에서는 먼저 WSHttpBinding 클래스의 인스턴스를 만든 다음 보안 모드를 Message로 설정하고 ClientCredentialTypeNone으로 설정합니다.

  2. CreateBindingElements 메서드를 사용하여 BindingElementCollection을 만듭니다.

  3. 컬렉션에서 SecurityBindingElement를 반환한 다음 SymmetricSecurityBindingElement 변수로 캐스팅합니다.

  4. LocalClientSecuritySettings 클래스의 IdentityVerifier 속성을 이전에 만든 CustomIdentityVerifier 클래스의 새 인스턴스로 설정합니다.

    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
    
    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);
    }
    
  5. 반환된 사용자 지정 바인딩을 사용하여 클라이언트 및 클래스의 인스턴스를 만듭니다. 그런 다음 클라이언트는 다음 코드에서와 같이 서비스에 대해 사용자 지정 ID 확인 검사를 수행할 수 있습니다.

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

예제

다음 예제에서는 IdentityVerifier 클래스의 전체 구현을 보여 줍니다.

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 = "https://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
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 == "https://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: {0}", claim.ClaimType);
                        Console.WriteLine("Right: {0}", claim.Right);
                        Console.WriteLine("Resource: {0}", claim.Resource);
                        Console.WriteLine();
                        returnvalue = true;
                    }
                }
            }

        }
        return returnvalue;
    }

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

다음 예제에서는 EndpointIdentity 클래스의 전체 구현을 보여 줍니다.

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
public class OrgEndpointIdentity : EndpointIdentity
{
    private string orgClaim;
    public OrgEndpointIdentity(string orgName)
    {
        orgClaim = orgName;
    }

    public string OrganizationClaim
    {
        get { return orgClaim; }
        set { orgClaim = value; }
    }
}

참고 항목

작업

Service Identity 샘플
권한 부여 정책
권한 부여 정책

참조

ServiceAuthorizationManager
EndpointIdentity
IdentityVerifier