방법: 사용자 지정 권한 부여 정책 만들기

WCF(Windows Communication Foundation)의 ID 모델 인프라에서는 클레임 기반의 권한 부여 모델을 지원합니다. 클레임은 토큰에서 추출되어 사용자 지정 권한 부여 정책에 의해 선택적으로 처리된 다음,이후에 권한 부여를 결정하기 위해 검사할 수 있는 AuthorizationContext에 배치됩니다. 사용자 지정 정책은 들어오는 토큰을 애플리케이션에서 필요로 하는 클레임으로 변형하는 데 사용할 수 있습니다. 이런 방식에서는 WCF에서 지원하는 다른 토큰 유형이 사용된 서로 다른 클레임에 대한 세부 사항이 애플리케이션 계층에 적용되지 않을 수 있습니다. 이 항목에서는 사용자 지정 권한 부여 정책을 구현하는 방법과 이 정책을 서비스에 사용된 정책 컬렉션에 추가하는 방법에 대해 설명합니다.

사용자 지정 권한 부여 정책을 구현하려면

  1. IAuthorizationPolicy에서 파생되는 새 클래스를 정의합니다.

  2. 클래스에 대해 생성자에서 고유 문자열을 생성하고 속성에 액세스할 때마다 해당 문자열을 반환하여 읽기 전용 Id 속성을 구현합니다.

  3. 정책 발급자를 나타내는Issuer를 반환하여 읽기 전용 ClaimSet 속성을 구현합니다. 이는 애플리케이션을 나타내는 ClaimSet이거나 기본 제공된ClaimSet(예를 들면 정적 ClaimSet 속성에 의해 반환된 System)일 수 있습니다.

  4. 다음 절차에 따라 Evaluate(EvaluationContext, Object) 메서드를 구현합니다.

Evaluate 메서드를 구현하려면

  1. 두 매개 변수인 개체 참조와 EvaluationContext 클래스의 인스턴스를 이 메서드에 전달합니다.

  2. EvaluationContext의 현재 콘텐츠에 관계없이 사용자 지정 권한 부여 정책을 통해 ClaimSet 인스턴스를 추가하려면, AddClaimSet(IAuthorizationPolicy, ClaimSet) 메서드를 호출하여 각 ClaimSet를 추가하고 Evaluate 메서드에서 true를 반환합니다. true가 반환되면 권한 부여 정책의 작업이 수행되어 이를 다시 호출할 필요가 없음을 권한 부여 인프라에 알립니다.

  3. 특정 클레임이 EvaluationContext에 이미 있는 경우에만 사용자 지정 권한 부여 정책을 통해 클레임 집합을 추가하려면 ClaimSet 속성에 의해 반환된 ClaimSets 인스턴스를 검사하여 이러한 클레임을 찾습니다. 클레임이 있으면 AddClaimSet(IAuthorizationPolicy, ClaimSet) 메서드를 호출하여 새로운 클레임 집합을 추가하고, 추가할 클레임 집합이 없으면 권한 부여 정책의 작업이 완료되었음을 권한 부여 인프라에 알리는 true를 반환합니다. 클레임이 없으면 false를 반환하는 데, 이는 다른 권한 부여 정책을 통해 클레임 집합을 EvaluationContext에 추가하려면 권한 부여 정책을 다시 호출해야 함을 알립니다.

  4. 더 복잡한 처리 시나리오에서는 Evaluate(EvaluationContext, Object) 메서드의 두 번째 매개 변수를 사용하여 상태 변수를 저장합니다. 이 상태 변수는 이후 각 호출 동안 특정 평가를 목적으로 권한 부여 인프라가 Evaluate(EvaluationContext, Object) 메서드에 다시 전달하는 변수입니다.

구성을 통해 사용자 지정 권한 부여 정책을 지정하려면

  1. policyType 요소에서 add 요소에 있는 authorizationPolicies 요소의 serviceAuthorization 특성에 사용자 지정 권한 부여 정책 유형을 지정합니다.

    <configuration>  
     <system.serviceModel>  
      <behaviors>  
        <serviceAuthorization serviceAuthorizationManagerType=  
                  "Samples.MyServiceAuthorizationManager" >  
          <authorizationPolicies>  
            <add policyType="Samples.MyAuthorizationPolicy" />  
          </authorizationPolicies>  
        </serviceAuthorization>  
      </behaviors>  
     </system.serviceModel>  
    </configuration>  
    

코드를 통해 사용자 지정 권한 부여 정책을 지정하려면

  1. List<T>IAuthorizationPolicy을 만듭니다.

  2. 사용자 지정 권한 부여 정책의 인스턴스를 만듭니다.

  3. 권한 부여 정책 인스턴스를 목록에 추가합니다.

  4. 각 사용자 지정 권한 부여 정책에 대해 2단계와 3단계를 반복합니다.

  5. 읽기 전용 버전의 목록을 ExternalAuthorizationPolicies 속성에 할당합니다.

    // Add a custom authorization policy to the service authorization behavior.
    List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>();
    policies.Add(new MyAuthorizationPolicy());
    serviceHost.Authorization.ExternalAuthorizationPolicies = policies.AsReadOnly();
    
    ' Add custom authorization policy to service authorization behavior.
    Dim policies As List(Of IAuthorizationPolicy) = New List(Of IAuthorizationPolicy)()
    policies.Add(New MyAuthorizationPolicy())
    serviceHost.Authorization.ExternalAuthorizationPolicies = policies.AsReadOnly()
    

예시

다음 예제에서는 전체 IAuthorizationPolicy 구현을 보여 줍니다.

public class MyAuthorizationPolicy : IAuthorizationPolicy
{
    string id;

    public MyAuthorizationPolicy()
    {
        id = Guid.NewGuid().ToString();
    }

    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        bool bRet = false;
        CustomAuthState customstate = null;

        // If the state is null, then this has not been called before so
        // set up a custom state.
        if (state == null)
        {
            customstate = new CustomAuthState();
            state = customstate;
        }
        else
        {
            customstate = (CustomAuthState)state;
        }

        // If claims have not been added yet...
        if (!customstate.ClaimsAdded)
        {
            // Create an empty list of claims.
            IList<Claim> claims = new List<Claim>();

            // Iterate through each of the claim sets in the evaluation context.
            foreach (ClaimSet cs in evaluationContext.ClaimSets)
                // Look for Name claims in the current claimset.
                foreach (Claim c in cs.FindClaims(ClaimTypes.Name, Rights.PossessProperty))
                    // Get the list of operations the given username is allowed to call.
                    foreach (string s in GetAllowedOpList(c.Resource.ToString()))
                    {
                        // Add claims to the list.
                        claims.Add(new Claim("http://example.org/claims/allowedoperation", s, Rights.PossessProperty));
                        Console.WriteLine("Claim added {0}", s);
                    }

            // Add claims to the evaluation context.
            evaluationContext.AddClaimSet(this, new DefaultClaimSet(this.Issuer, claims));

            // Record that claims were added.
            customstate.ClaimsAdded = true;

            // Return true, indicating that this method does not need to be called again.
            bRet = true;
        }
        else
        {
            // Should never get here, but just in case, return true.
            bRet = true;
        }

        return bRet;
    }

    public ClaimSet Issuer
    {
        get { return ClaimSet.System; }
    }

    public string Id
    {
        get { return id; }
    }

    // This method returns a collection of action strings that indicate the
    // operations the specified username is allowed to call.
    private IEnumerable<string> GetAllowedOpList(string username)
    {
        IList<string> ret = new List<string>();

        if (username == "test1")
        {
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Add");
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Multiply");
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Subtract");
        }
        else if (username == "test2")
        {
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Add");
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Subtract");
        }
        return ret;
    }

    // Internal class for keeping track of state.
    class CustomAuthState
    {
        bool bClaimsAdded;

        public CustomAuthState()
        {
            bClaimsAdded = false;
        }

        public bool ClaimsAdded
        {
            get { return bClaimsAdded; }
            set { bClaimsAdded = value; }
        }
    }
}

Public Class MyAuthorizationPolicy
    Implements IAuthorizationPolicy
    Private id_Value As String


    Public Sub New()
        id_Value = Guid.NewGuid().ToString()

    End Sub


    Public Function Evaluate(ByVal evaluationContext As EvaluationContext, ByRef state As Object) As Boolean _
        Implements IAuthorizationPolicy.Evaluate
        Dim bRet As Boolean = False
        Dim customstate As CustomAuthState = Nothing

        ' If the state is null, then this has not been called before, so set up
        ' our custom state.
        If state Is Nothing Then
            customstate = New CustomAuthState()
            state = customstate
        Else
            customstate = CType(state, CustomAuthState)
        End If
        ' If claims have not been added yet...
        If Not customstate.ClaimsAdded Then
            ' Create an empty list of Claims.
            Dim claims as IList(Of Claim) = New List(Of Claim)()

            ' Iterate through each of the claimsets in the evaluation context.
            Dim cs As ClaimSet
            For Each cs In evaluationContext.ClaimSets
                ' Look for Name claims in the current claimset...
                Dim c As Claim
                For Each c In cs.FindClaims(ClaimTypes.Name, Rights.PossessProperty)
                    ' Get the list of operations that the given username is allowed to call.
                    Dim s As String
                    For Each s In GetAllowedOpList(c.Resource.ToString())
                        ' Add claims to the list.
                        claims.Add(New Claim("http://example.org/claims/allowedoperation", s, Rights.PossessProperty))
                        Console.WriteLine("Claim added {0}", s)
                    Next s
                Next c
            Next cs ' Add claims to the evaluation context.
            evaluationContext.AddClaimSet(Me, New DefaultClaimSet(Me.Issuer, claims))

            ' Record that claims were added.
            customstate.ClaimsAdded = True

            ' Return true, indicating that this does not need to be called again.
            bRet = True
        Else
            ' Should never get here, but just in case...
            bRet = True
        End If


        Return bRet

    End Function

    Public ReadOnly Property Issuer() As ClaimSet Implements IAuthorizationPolicy.Issuer
        Get
            Return ClaimSet.System
        End Get
    End Property

    Public ReadOnly Property Id() As String Implements IAuthorizationPolicy.Id
        Get
            Return id_Value
        End Get
    End Property
    ' This method returns a collection of action strings that indicate the
    ' operations the specified username is allowed to call.

    ' Operations the specified username is allowed to call.
    Private Function GetAllowedOpList(ByVal userName As String) As IEnumerable(Of String)
        Dim ret As IList(Of String) = new List(Of String)()
        If username = "test1" Then
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Add")
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Multiply")
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Subtract")
        ElseIf username = "test2" Then
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Add")
            ret.Add("http://Microsoft.ServiceModel.Samples/ICalculator/Subtract")
        End If
        Return ret
    End Function

    ' internal class for keeping track of state

    Class CustomAuthState
        Private bClaimsAdded As Boolean


        Public Sub New()
            bClaimsAdded = False

        End Sub


        Public Property ClaimsAdded() As Boolean
            Get
                Return bClaimsAdded
            End Get
            Set
                bClaimsAdded = value
            End Set
        End Property
    End Class
End Class

참고 항목