Поделиться через


Как создавать пользовательский диспетчер авторизации для службы

Инфраструктура модели удостоверения в Windows Communication Foundation (WCF) поддерживает расширяемую модель авторизации, основанную на утверждениях. Утверждения извлекаются из маркеров, дополнительно обрабатываемых пользовательской политикой авторизации, и затем помещаются в контекст AuthorizationContext. Диспетчер авторизации проверяет утверждения в контексте AuthorizationContext для принятия решений об авторизации.

По умолчанию решения об авторизации принимаются классом ServiceAuthorizationManager; однако эти решения можно переопределить, создав пользовательский диспетчер авторизации. Чтобы создать пользовательский диспетчер авторизации, создайте класс, наследующий от класса ServiceAuthorizationManager, и реализуйте метод CheckAccessCore. Решения об авторизации принимаются в методе CheckAccessCore, который возвращает true, если доступ предоставлен, и false, если в доступе отказано.

Если решение об авторизации зависит от содержимого тела сообщения, используйте метод CheckAccess.

В связи с вопросами производительности при возможности следует внести изменения в приложение, чтобы решение об авторизации не требовало доступа к телу сообщения.

Пользовательский диспетчер авторизации для службы можно зарегистрировать в коде или конфигурации.

Создание пользовательского диспетчера авторизации

  1. Создайте класс, производный от класса ServiceAuthorizationManager.

    Public Class MyServiceAuthorizationManager
        Inherits ServiceAuthorizationManager
    
    
    public class MyServiceAuthorizationManager : ServiceAuthorizationManager
    {
    
  2. Переопределите метод CheckAccessCore.

    Для принятия решения об авторизации используйте метод OperationContext, передаваемый в метод CheckAccessCore.

    В следующем примере кода метод FindClaims используется для поиска пользовательского утверждения https://www.contoso.com/claims/allowedoperation и принятия решения об авторизации.

    Protected Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean 
        ' Extract the action URI from the OperationContext. Match this against the claims.
        ' in the AuthorizationContext.
        Dim action As String = operationContext.RequestContext.RequestMessage.Headers.Action
    
        ' Iterate through the various claimsets in the AuthorizationContext.
        Dim cs As ClaimSet
        For Each cs In  operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets
            ' Examine only those claim sets issued by System.
            If cs.Issuer Is ClaimSet.System Then
                ' Iterate through claims of type "https://www.contoso.com/claims/allowedoperation".
                Dim c As Claim
                For Each c In  cs.FindClaims("https://www.contoso.com/claims/allowedoperation", _
                     Rights.PossessProperty)
                    ' If the Claim resource matches the action URI then return true to allow access.
                    If action = c.Resource.ToString() Then
                        Return True
                    End If
                Next c
            End If
        Next cs 
        ' If this point is reached, return false to deny access.
        Return False
    
    End Function 
    
    protected override bool CheckAccessCore(OperationContext operationContext)
    {                
      // Extract the action URI from the OperationContext. Match this against the claims
      // in the AuthorizationContext.
      string action = operationContext.RequestContext.RequestMessage.Headers.Action;
    
      // Iterate through the various claim sets in the AuthorizationContext.
      foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
      {
        // Examine only those claim sets issued by System.
        if (cs.Issuer == ClaimSet.System)
        {
          // Iterate through claims of type "https://www.contoso.com/claims/allowedoperation".
            foreach (Claim c in cs.FindClaims("https://www.contoso.com/claims/allowedoperation", Rights.PossessProperty))
          {
            // If the Claim resource matches the action URI then return true to allow access.
            if (action == c.Resource.ToString())
              return true;
          }
        }
      }
    
      // If this point is reached, return false to deny access.
      return false;                 
    }
    

Регистрация пользовательского диспетчера авторизации с помощью кода

  1. Создайте экземпляр пользовательского диспетчера авторизации и назначьте его свойству ServiceAuthorizationManager.

    Доступ к поведению ServiceAuthorizationBehavior возможен с помощью свойства Authorization.

    В следующем примере кода регистрируется пользовательский диспетчер авторизации MyServiceAuthorizationManager.

    ' Add a custom authorization manager to the service authorization behavior.
    serviceHost.Authorization.ServiceAuthorizationManager = _
        New MyServiceAuthorizationManager()
    
    // Add a custom authorization manager to the service authorization behavior.
    serviceHost.Authorization.ServiceAuthorizationManager = 
               new MyServiceAuthorizationManager();
    

Регистрация пользовательского диспетчера авторизации с помощью конфигурации

  1. Откройте файл конфигурации службы.

  2. Добавьте элемент serviceAuthorization element в элемент Behaviors element.

    Добавьте в элемент serviceAuthorization element атрибут serviceAuthorizationManagerType и установите для него значение типа, представляющего пользовательский диспетчер авторизации.

  3. Добавьте привязку, обеспечивающую безопасность связи между клиентом и службой.

    Привязка, выбранная для этой связи, определяет утверждения, добавляемые в контекст AuthorizationContext и используемые пользовательским диспетчером авторизации для принятия решений об авторизации. Дополнительные сведения о привязках, предоставляемых системой, см. в разделе Привязки, предоставляемые системой.

  4. Свяжите поведение с конечной точкой службы, добавив элемент <service> и задав для атрибута behaviorConfiguration значение атрибута name элемента <behavior> of <serviceBehaviors>.

    Дополнительные сведения о настройке конечной точки службы см. в разделе Практическое руководство. Создание конечной точки службы в конфигурации.

    В следующем примере кода регистрируется пользовательский диспетчер авторизации Samples.MyServiceAuthorizationManager.

    <configuration>
      <system.serviceModel>
        <services>
          <service 
              name="Microsoft.ServiceModel.Samples.CalculatorService"
              behaviorConfiguration="CalculatorServiceBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="https://localhost:8000/ServiceModelSamples/service"/>
              </baseAddresses>
            </host>
            <endpoint address=""
                      binding="wsHttpBinding_Calculator"
                      contract="Microsoft.ServiceModel.Samples.ICalculator" />
          </service>
        </services>
        <bindings>
          <WSHttpBinding>
           <binding name = "wsHttpBinding_Calculator">
             <security mode="Message">
               <message clientCredentialType="Windows"/>
             </security>
            </binding>
          </WSHttpBinding>
    </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior name="CalculatorServiceBehavior">
              <serviceAuthorization serviceAuthorizationManagerType="Samples.MyServiceAuthorizationManager" />
            </behaviors>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>
    

Пример

В следующем образце кода показана базовая реализация класса ServiceAuthorizationManager, которая содержит переопределение метода CheckAccessCore. В этом примере кода производится проверка AuthorizationContext на наличие пользовательского утверждения и возвращается true, если ресурс для этого пользовательского утверждения соответствует значению действия из контекста OperationContext. Более полная реализация класса ServiceAuthorizationManager содержится в разделе Политика авторизации.

Public Class MyServiceAuthorizationManager
    Inherits ServiceAuthorizationManager
    
    Protected Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean 
        ' Extract the action URI from the OperationContext. Match this against the claims.
        ' in the AuthorizationContext.
        Dim action As String = operationContext.RequestContext.RequestMessage.Headers.Action
        
        ' Iterate through the various claimsets in the AuthorizationContext.
        Dim cs As ClaimSet
        For Each cs In  operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets
            ' Examine only those claim sets issued by System.
            If cs.Issuer Is ClaimSet.System Then
                ' Iterate through claims of type "https://www.contoso.com/claims/allowedoperation".
                Dim c As Claim
                For Each c In  cs.FindClaims("https://www.contoso.com/claims/allowedoperation", _
                     Rights.PossessProperty)
                    ' If the Claim resource matches the action URI then return true to allow access.
                    If action = c.Resource.ToString() Then
                        Return True
                    End If
                Next c
            End If
        Next cs 
        ' If this point is reached, return false to deny access.
        Return False
    
    End Function 
End Class 
public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
  protected override bool CheckAccessCore(OperationContext operationContext)
  {                
    // Extract the action URI from the OperationContext. Match this against the claims
    // in the AuthorizationContext.
    string action = operationContext.RequestContext.RequestMessage.Headers.Action;
    
    // Iterate through the various claim sets in the AuthorizationContext.
    foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
    {
      // Examine only those claim sets issued by System.
      if (cs.Issuer == ClaimSet.System)
      {
        // Iterate through claims of type "https://www.contoso.com/claims/allowedoperation".
          foreach (Claim c in cs.FindClaims("https://www.contoso.com/claims/allowedoperation", Rights.PossessProperty))
        {
          // If the Claim resource matches the action URI then return true to allow access.
          if (action == c.Resource.ToString())
            return true;
        }
      }
    }
    
    // If this point is reached, return false to deny access.
    return false;                 
  }
}

См. также

Задачи

Политика авторизации
Политика авторизации

Справочник

ServiceAuthorizationManager