Autorización personalizada en Asp.net WebApi: ¿qué lío?

113

Estoy leyendo varios recursos (libros y respuestas SO) sobre la autorización en WebApi.

Supongamos que quiero agregar un atributo personalizado que permite el acceso solo para ciertos usuarios:

Caso 1

He visto este enfoque de anulación OnAuthorization , que establece la respuesta si algo está mal

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 public override void OnAuthorization(HttpActionContext actionContext)
  {
   if ( /*check if user OK or not*/)
   {
     actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
   }
  }
}

Caso # 2

Pero también he visto este ejemplo similar que también anula OnAuthorizationpero con llamadas a base:

public override void OnAuthorization(HttpActionContext actionContext) 
{ 
  base.OnAuthorization(actionContext);

    // If not authorized at all, don't bother

    if (actionContext.Response == null)  
     {
      //...
     }
}

Luego, verifica si HttpActionContext.Responseestá configurado o no. Si no está configurado, significa que la solicitud está autorizada y el usuario está bien

Caso # 3

Pero también he visto este enfoque de anular IsAuthorized :

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 protected override bool IsAuthorized(HttpActionContext context)
  {
   if ( /*check if user OK or not*/)
   {
    return true;// or false
   }
  }
}

Caso # 4

Y luego vi un ejemplo similar pero con una llamada base.IsAuthorized (context):

protected override bool IsAuthorized(HttpActionContext context)
{
 if (something1 && something2 && base.IsAuthorized(context)) //??
 return true;
 return false;
}

Una cosa más

Y finalmente Dominick dijo aquí :

No debe anular OnAuthorization, ya que se estaría perdiendo el control de [AllowAnonymous].

Preguntas

  • 1) ¿Qué métodos debo utilizar: IsAuthorizedo OnAuthorization? (o cuándo usar cuál)

  • 2) ¿Cuándo debo llamar a base.IsAuthorized orbase.OnAuthorization`?

  • 3) ¿Así es como lo construyeron? que si la respuesta es nula entonces todo esta bien? (caso # 2)

nótese bien

Tenga en cuenta que estoy usando (y quiero usar) solo lo AuthorizeAttributeque ya hereda de AuthorizationFilterAttribute

Por qué ?

Porque estoy en la primera etapa en: http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

ingrese la descripción de la imagen aquí

De todos modos, estoy preguntando mediante la ampliación del atributo Authorize.

Royi Namir
fuente
¿Qué necesita para anular el atributo Authorize? ¿Cuál es el caso de uso que desea lograr? Si necesita permitir el acceso a ciertos usuarios, ¿por qué no utilizar el atributo [Authorize (Users = "Admin")] como este?
Taiseer Joudeh
1
@TaiseerJoudeh Por ejemplo Intente autorizar a los usuarios entre las 10:00 y las 12:00 (configurable). no puede hacer eso con roles simples y atributos autorizados. tienes que hacer tu propia lógica
Royi Namir

Respuestas:

93

¿Qué métodos debo utilizar: IsAuthorized u OnAuthorization? (o cuándo usar cuál)

Extenderá AuthorizationFilterAttributesi su lógica de autorización no depende de la identidad establecida y los roles. Para la autorización relacionada con el usuario, extenderá y usará AuthorizeAttribute. Para el primer caso, anulará OnAuthorization. Para el último caso, anulará IsAuthorized. Como puede ver en el código fuente de estos atributos, OnAuthorizationestá marcado como virtual para que lo anule si deriva de AuthorizationFilterAttribute. Por otro lado, el IsAuthorizedmétodo está marcado como virtual en AuthorizeAttribute. Creo que este es un buen indicador del uso previsto.

¿Cuándo debo llamar a base.IsAuthorized o base.OnAuthorization?

La respuesta a esta pregunta radica en cómo funciona OO en general. Si anula un método, puede proporcionar completamente una nueva implementación o aprovechar la implementación proporcionada por el padre y mejorar el comportamiento. Por ejemplo, tome el caso de IsAuthorized(HttpActionContext). El comportamiento de la clase base es verificar el usuario / rol con lo que se especifica en el filtro frente a la identidad establecida. Digamos que desea hacer todo eso, pero además, desea verificar otra cosa, puede basarse en un encabezado de solicitud o algo así. En ese caso, puede proporcionar una anulación como esta.

protected override bool IsAuthorized(HttpActionContext actionContext)
{
    bool isAuthroized = base.IsAuthorized(actionContext);
    // Here you look at the header and do your additional stuff based on actionContext
    // and store the result in isRequestHeaderOk
    // Then, you can combine the results
    // return isAuthorized && isRequestHeaderOk;
}

Lo siento, pero no entiendo su Q3. Por cierto, el filtro de autorización ha existido durante mucho tiempo y la gente lo usa para todo tipo de cosas y, a veces, también de manera incorrecta.

Una cosa más. Y finalmente hubo un tipo aquí que dijo: No debería anular OnAuthorization, porque se estaría perdiendo el manejo de [AllowAnonymous].

El tipo que dijo eso es el Dios del control de acceso: Dominick. Obviamente será correcto. Si observa la implementación de OnAuthorization(copiado a continuación),

public override void OnAuthorization(HttpActionContext actionContext)
{
    if (actionContext == null)
    {
        throw Error.ArgumentNull("actionContext");
    }

    if (SkipAuthorization(actionContext))
    {
        return;
    }

    if (!IsAuthorized(actionContext))
    {
        HandleUnauthorizedRequest(actionContext);
    }
}

la llamada a SkipAuthorizationes la parte que garantiza que AllowAnonymousse apliquen los filtros, es decir, que se omita la autorización. Si anula este método, pierde ese comportamiento. En realidad, si decide basar su autorización en usuarios / roles, en ese momento habría decidido derivar de AuthorizeAttribute. La única opción correcta que le queda en ese momento será anular IsAuthorizedy no la ya anulada OnAuthorization, aunque técnicamente es posible hacer cualquiera de las dos.

PD. En ASP.NET Web API, hay otro filtro llamado filtro de autenticación. La idea es que use eso para la autenticación y el filtro de autorización para la autorización, como su nombre lo indica. Sin embargo, hay muchos ejemplos en los que se manipula este límite. Muchos ejemplos de filtros de autorización harán algún tipo de autenticación. De todos modos, si tiene tiempo y quiere entender un poco más, eche un vistazo a este artículo de MSDN . Descargo de responsabilidad: fue escrito por mí.

Badri
fuente
Gracias de nuevo, pero si leo entre líneas, IsAuthenticated es llamado por OnAuthirization, entonces ¿por qué no anular OnAuthorization y llamar a base.OnAuthorization y luego verificar la respuesta?
Royi Namir
Seguro que puedes, si eso es lo que quieres.
Badri
En mi tercera pregunta quise decir: después de ejecutar la función base - base.OnAuthorization, por ejemplo, ¿la única forma de verificar si fue exitosa- es inspeccionar la propiedad Response ?, ps los ejemplos son de su libro :-)
Royi Namir
Sí, normalmente busca el código de estado 401 pero no nulo, hasta donde yo sé. Por cierto, no recuerdo haber escrito sobre anular OnAuthorizationen mi libro. Estoy seguro de que no habría escrito sobre la verificación de la respuesta en busca de nulos, porque esta es la primera vez que escucho sobre ello :)
Badri
Sí, me confundí con el otro libro. Estoy leyendo 3 libros simultáneamente: securty (el tuyo), práctico (el tuyo) y webapi pro (Tugberk's, Zeitler, Ali). Como puede ver, lo hicieron allí: i.stack.imgur.com/LNGi4.jpg - simplemente comprobaron si es nulo, ¿debo verificar los códigos nulos o de error?
Royi Namir
18

Ok, mi sugerencia es hacer lo siguiente asumiendo que está utilizando tokens de portador de OAuth para proteger su API web y está configurando el valor permitido como un reclamo para el usuario cuando emitió el token. Puede leer más sobre la autenticación basada en token aquí

  1. Cree CustomAuthorizeAttribute que se deriva de AuthorizationFilterAttribute
  2. anular el método OnAuthorizationAsyncy utilizar el código de muestra a continuación:

     public class CustomAuthorizeAttribute : AuthorizationFilterAttribute
    {
    
        public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
    
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
    
            if (!principal.Identity.IsAuthenticated)
            {
                return Task.FromResult<object>(null);
            }
    
            var userName = principal.FindFirst(ClaimTypes.Name).Value;
            var userAllowedTime = principal.FindFirst("userAllowedTime").Value;
    
            if (currentTime != userAllowedTime)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Not allowed to access...bla bla");
                return Task.FromResult<object>(null);
            }
    
            //User is Authorized, complete execution
            return Task.FromResult<object>(null);
    
        }
    }
  3. Ahora, en sus controladores, utiliza el atributo CustomAuthorize para proteger sus controladores mediante esta lógica de autorización.
Taiseer Joudeh
fuente
1
Gracias. Pero actualmente estoy usando AuthorizeAttributecuál hereda AuthorizationFilterAttributey, también para aprender, pregunté específicamente sobre qué método debería usar y sobre la respuesta tiene contenido o no ...
Royi Namir
3

ASP.NET v5 introdujo un sistema de autorización completamente nuevo. Para aquellos que van a usar .NET 5, les sugiero que se pasen a Microsoft.AspNet.Authorization.

Básicamente envuelve el desorden causado por mantener ambos System.Web.Http.AuthorizeySystem.Web.Mvc.Authorize y otras implementaciones de autenticación mayores.

Proporciona una muy buena abstracción de tipos de acción (crear, leer, actualizar, eliminar), recursos, roles, reclamaciones, vistas, requisitos personalizados y permite crear controladores personalizados, combinando cualquiera de los anteriores. Además, esos manipuladores también se pueden utilizar en combinación.

En ASP.NET v5, la autorización ahora proporciona un rol declarativo simple y un modelo basado en políticas más rico donde la autorización se expresa en requisitos y los controladores evalúan las reclamaciones de los usuarios contra los requisitos. Las verificaciones imperativas pueden basarse en políticas simples o políticas que evalúan tanto la identidad del usuario como las propiedades del recurso al que el usuario está intentando acceder.

Anestis Kivranoglou
fuente
14
Es bueno saberlo, pero no responde la pregunta en absoluto.
Zero3