다음을 통해 공유


방법: 사용자 지정 보안 토큰 인증자 만들기

이 항목에서는 사용자 지정 보안 토큰 인증자를 만드는 방법과 이를 사용자 지정 보안 토큰 관리자와 통합하는 방법에 대해 설명합니다. 보안 토큰 인증자는 들어오는 메시지와 함께 제공된 보안 토큰 내용의 유효성을 검사합니다. 유효성 검사에 성공하면, 인증자는 평가 시 클레임 집합이 반환되는 IAuthorizationPolicy 인스턴스 컬렉션을 반환합니다.

WCF(Windows Communication Foundation)에서 사용자 지정 보안 토큰 인증자를 사용하려면 먼저 사용자 지정 자격 증명과 보안 토큰 관리자 구현을 만들어야 합니다. 사용자 지정 자격 증명 및 보안 토큰 관리자를 만드는 방법에 대한 자세한 내용은 연습: 사용자 지정 클라이언트 및 서비스 자격 증명 만들기를 참조하세요.

절차

사용자 지정 보안 토큰 인증자를 만들려면

  1. SecurityTokenAuthenticator 클래스에서 파생된 새 클래스를 정의합니다.

  2. CanValidateTokenCore 메서드를 재정의합니다. 사용자 지정 인증자가 들어오는 토큰 형식의 유효성을 검사할 수 있는지 여부에 따라 메서드에서 true 또는 false를 반환합니다.

  3. ValidateTokenCore 메서드를 재정의합니다. 이 메서드는 토큰 내용의 유효성을 검사하는 데 필요합니다. 토큰이 유효성 검사 단계를 통과하면 메서드가 IAuthorizationPolicy 인스턴스의 컬렉션을 반환합니다. 다음 예제에서는 다음 절차에서 만들 사용자 지정 권한 부여 정책 구현이 사용됩니다.

    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
    

이전 코드는 CanValidateToken(SecurityToken) 메서드에서 권한 부여 정책 컬렉션을 반환합니다. WCF는 이 인터페이스의 퍼블릭 구현을 제공하지 않습니다. 다음 절차에서는 사용자 요구 사항에 맞게 이를 수행하는 방법을 보여 줍니다.

사용자 지정 권한 부여 정책을 만들려면

  1. IAuthorizationPolicy 인터페이스를 구현하는 새 클래스를 정의합니다.

  2. Id 읽기 전용 속성을 구현합니다. 이 속성을 구현하는 한 가지 방법은 클래스 생성자로 GUID(Globally Unique Identifier)를 만든 다음 이 속성 값이 요청될 때마다 이를 반환하는 것입니다.

  3. Issuer 읽기 전용 속성을 구현합니다. 이 속성은 토큰에서 가져오는 클레임 집합 발급자를 반환하는 데 필요합니다. 이 발급자는 토큰 발급자이거나 토큰 내용의 유효성을 검사하는 인증 기관이어야 합니다. 다음 예제에서는 이전 절차에서 만든 사용자 지정 보안 토큰 인증자로부터 이 클래스에 전달된 발급자 클레임을 사용합니다. 사용자 지정 보안 토큰 인증자는 System 속성을 통해 반환된 시스템 제공 클레임 집합을 사용하여, 사용자 이름 토큰의 발급자를 나타냅니다.

  4. Evaluate 메서드를 구현합니다. 이 메서드는 인수로 전달된 EvaluationContext 클래스의 인스턴스를 들어오는 보안 토큰의 내용을 바탕으로 하는 클레임으로 채웁니다. 평가 시 이 작업이 완료되면 메서드는 true를 반환합니다. 평가 컨텍스트에 추가 정보를 제공하는 다른 권한 부여 정책을 사용하여 구현하는 경우, 필요한 정보가 평가 컨텍스트에 아직 없으면 이 메서드는 false를 반환할 수 있습니다. 이때 권한 부여 정책 중 하나 이상의 정책에 의해 평가 컨텍스트가 수정되면, WCF에서는 들어오는 메시지에 대해 생성된 기타 권한 부여 정책을 모두 평가한 후 이 메서드를 다시 호출합니다.

    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
    

연습: 사용자 지정 클라이언트 및 서비스 자격 증명 만들기에서는 사용자 지정 자격 증명 및 사용자 지정 보안 토큰 관리자를 만드는 방법을 설명합니다. 여기에서 만든 사용자 지정 보안 토큰 인증자를 사용하기 위해 CreateSecurityTokenAuthenticator 메서드에서 사용자 지정 인증자를 반환하도록 보안 토큰 관리자의 구현이 수정됩니다. 올바른 보안 토큰 요구 사항이 전달되면 메서드에서 인증자를 반환합니다.

사용자 지정 보안 토큰 인증자를 사용자 지정 보안 토큰 관리자와 통합하려면

  1. 사용자 지정 보안 토큰 관리자 구현에서 CreateSecurityTokenAuthenticator 메서드를 재정의합니다.

  2. 메서드에 논리를 추가하여SecurityTokenRequirement 매개 변수를 기반으로 사용자 지정 보안 토큰 인증자를 반환할 수 있도록 합니다. 다음 예제에서는 토큰에서 요구하는 토큰 형식이 사용자 이름(UserName 속성으로 나타냄)이고 요청되는 보안 토큰 인증자에 대한 메시지 방향이 입력(Input 필드로 나타냄)이면 사용자 지정 보안 토큰 인증자를 반환합니다.

    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
    

참고 항목