Crear un atributo de autorización personalizado

En este tema se muestra cómo agregar un atributo personalizado para la autorización. El marco de WCF RIA Services proporciona los atributos RequiresRoleAttribute y RequiresAuthenticationAttribute. Estos atributos permiten especificar fácilmente qué operaciones de dominio solo están disponibles para los usuarios autenticados o para los usuarios pertenecientes a un rol concreto. Además de estos dos atributos, se puede crear un atributo que represente la lógica de autorización personalizada y aplicarlo después a las operaciones de dominio.

Cuando se expone un servicio de dominio, este servicio de dominio está disponible para todos los usuarios en la red. No se puede suponer que una aplicación cliente propia es la única aplicación que tendrá acceso al servicio de dominio. Se pueden utilizar atributos de autenticación personalizados para restringir el acceso a las operaciones de dominio aun cuando se tenga acceso a la operación de dominio desde fuera de la aplicación cliente.

En este tema creará un atributo de autorización personalizado mediante la creación de una clase que deriva de AuthorizationAttribute y el reemplazo del método IsAuthorized para proporcionar la lógica personalizada propia. Puede utilizar los parámetros IPrincipal y AuthorizationContext para tener acceso a información que pueda necesitar dentro de su código de autenticación personalizado. El objeto AuthorizationContext es null en operaciones de consulta.

Para crear un atributo de autorización personalizado

  1. En el proyecto de servidor, cree una clase que derive de AuthorizationAttribute.

  2. Reemplace el método IsAuthorized y agregue lógica para determinar la autorización.

    En el ejemplo siguiente se muestra un atributo personalizado denominado RestrictAccessToAssignedManagers que comprueba si el usuario autenticado es el superior del empleado cuyo registro de EmployeePayHistory se está modificando.

    Public Class RestrictAccessToAssignedManagers
        Inherits AuthorizationAttribute
    
        Protected Overrides Function IsAuthorized(ByVal principal As System.Security.Principal.IPrincipal, ByVal authorizationContext As System.ComponentModel.DataAnnotations.AuthorizationContext) As System.ComponentModel.DataAnnotations.AuthorizationResult
            Dim eph As EmployeePayHistory
            Dim selectedEmployee As Employee
            Dim authenticatedUser As Employee
    
            eph = CType(authorizationContext.Instance, EmployeePayHistory)
    
            Using context As New AdventureWorksEntities()
                selectedEmployee = context.Employees.SingleOrDefault(Function(e) e.EmployeeID = eph.EmployeeID)
                authenticatedUser = context.Employees.SingleOrDefault(Function(e) e.LoginID = principal.Identity.Name)
            End Using
    
            If (selectedEmployee.ManagerID = authenticatedUser.EmployeeID) Then
                Return AuthorizationResult.Allowed
            Else
                Return New AuthorizationResult("Only the authenticated manager for the employee can add a new record.")
            End If
        End Function
    End Class
    
    public class RestrictAccessToAssignedManagers : AuthorizationAttribute
    {
        protected override AuthorizationResult IsAuthorized(System.Security.Principal.IPrincipal principal, AuthorizationContext authorizationContext)
        {
            EmployeePayHistory eph = (EmployeePayHistory)authorizationContext.Instance;
            Employee selectedEmployee;
            Employee authenticatedUser;
    
            using (AdventureWorksEntities context = new AdventureWorksEntities())
            {
                selectedEmployee = context.Employees.SingleOrDefault(e => e.EmployeeID == eph.EmployeeID);
                authenticatedUser = context.Employees.SingleOrDefault(e => e.LoginID == principal.Identity.Name);
            }
    
            if (selectedEmployee.ManagerID == authenticatedUser.EmployeeID)
            {
                return AuthorizationResult.Allowed;
            }
            else
            {
                return new AuthorizationResult("Only the authenticated manager for the employee can add a new record.");
            }
        }
    }
    
  3. Para realizar la lógica de autorización personalizada, aplique el atributo de autorización personalizado a la operación de dominio.

    En el ejemplo siguiente se muestra el atributo RestrictAccessToAssignedManagers aplicado a una operación de dominio.

    <RestrictAccessToAssignedManagers()> _
    Public Sub InsertEmployeePayHistory(ByVal employeePayHistory As EmployeePayHistory)
        If ((employeePayHistory.EntityState = EntityState.Detached) _
                    = False) Then
            Me.ObjectContext.ObjectStateManager.ChangeObjectState(employeePayHistory, EntityState.Added)
        Else
            Me.ObjectContext.EmployeePayHistories.AddObject(employeePayHistory)
        End If
    End Sub
    
    [RestrictAccessToAssignedManagers]
    public void InsertEmployeePayHistory(EmployeePayHistory employeePayHistory)
    {
        if ((employeePayHistory.EntityState != EntityState.Detached))
        {
            this.ObjectContext.ObjectStateManager.ChangeObjectState(employeePayHistory, EntityState.Added);
        }
        else
        {
            this.ObjectContext.EmployeePayHistories.AddObject(employeePayHistory);
        }
    }