Cómo crear un administrador de autorización personalizado para un servicio

La infraestructura del Modelo de identidad en Windows Communication Foundation (WCF) admite un modelo de la autorización basado en demandas extensible. Las demandas se extraen de los tokens y opcionalmente son procesadas por directivas de autorización personalizadas y, a continuación, colocadas en AuthorizationContext. Un administrador de autorización examina las demandas en AuthorizationContext para tomar las decisiones de autorización.

La clase ServiceAuthorizationManager toma de forma predeterminada, las decisiones de la autorización; sin embargo estas decisiones se pueden invalidar creando un administrador de autorización personalizado. Para crear un administrador de autorización personalizado, cree una clase que derive de ServiceAuthorizationManager e implemente el método CheckAccessCore. Las decisiones de la autorización se toman en el método CheckAccessCore, que devuelve true cuando se permite el acceso y false cuando se niega el acceso.

Si la decisión de autorización depende del contenido del cuerpo del mensaje, utilice el método CheckAccess.

Debido a los problemas de rendimiento, en la medida de lo posible debe rediseñar su aplicación para que la decisión de autorización no requiera el acceso al cuerpo del mensaje.

El registro del administrador de autorización personalizado para un servicio se puede hacer en código o configuración.

Para crear un administrador de autorización personalizado

  1. Derive una clase de la clase ServiceAuthorizationManager.

    Public Class MyServiceAuthorizationManager
        Inherits ServiceAuthorizationManager
    
    
    public class MyServiceAuthorizationManager : ServiceAuthorizationManager
    {
    
  2. Invalide el método CheckAccessCore.

    Utilice el OperationContext que se pasa al método CheckAccessCore para tomar las decisiones de autorización.

    El siguiente ejemplo de código utiliza el método FindClaims para buscar el https://www.contoso.com/claims/allowedoperation de la notificación personalizada y tomar una decisión de autorización.

    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;                 
    }
    

Para registrar a un administrador de autorización personalizado mediante código

  1. Cree una instancia del administrador de autorización personalizado y asígnelo a la propiedad ServiceAuthorizationManager.

    Se puede tener acceso a ServiceAuthorizationBehavior mediante la propiedad Authorization.

    El ejemplo de código siguiente registra el administrador de autorización personalizado 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();
    

Para registrar a un administrador de autorización personalizado mediante configuración

  1. Abra el archivo de configuración para el servicio.

  2. Agregue serviceAuthorization element a Behaviors element.

    Para el serviceAuthorization element, agregue un atributo serviceAuthorizationManagerType y establezca su valor en el tipo que represente al administrador de autorización personalizado.

  3. Agregue un enlace que proteja la comunicación entre el cliente y el servicio.

    El enlace que se elige para esta comunicación determina las demandas que se agregan al AuthorizationContext, que el administrador de autorización personalizado utiliza para tomar las decisiones de autorización. Para obtener más detalles sobre los enlaces proporcionados por el sistema, vea Enlaces proporcionados por el sistema.

  4. Asocie el comportamiento a un extremo de servicio, agregando un elemento <service>behaviorConfiguration y establezca el valor del atributo <behavior> of <serviceBehaviors> en el valor del atributo de nombre para el elemento.

    Para obtener más información sobre la configuración de un extremo de servicio, vea Cómo crear un extremo de servicio en configuración.

    El ejemplo de código siguiente registra el administrador de autorización personalizado 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>
    

Ejemplo

El ejemplo de código siguiente muestra una implementación básica de una clase ServiceAuthorizationManager que incluye la invalidación del método CheckAccessCore. El código de ejemplo examina AuthorizationContext para una demanda personalizada y devuelve true cuando el recurso para esa demanda de la costumbre coincide con el valor de la acción de OperationContext. Para una implementación más completa de una clase ServiceAuthorizationManager, vea Directiva de autorización.

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;                 
  }
}

Vea también

Tareas

Directiva de autorización
Directiva de autorización

Referencia

ServiceAuthorizationManager