FilterProvider condicional para WebAPI

Tengo una aplicación ASP.NET MVC/WebAPI/AngularJS en la que quiero implementar la protección CSRF. He encontrado algunas soluciones geniales en esto, pero me falta una pieza del rompecabezas. Quiero poder aplicar automáticamente un AuthorizationAttribute personalizado a los métodos no seguros de la API (POST, PUT, etc.). Espero que alguien pueda ayudar.

En el lado de MVC, estoy usando MVC AntiForgeryToken junto con Proveedor de filtro condicional de Phil Haacked, configurado para aplicar el atributo ValidateAntiForgeryToken a todos los métodos POST. La técnica se explica en esta publicación. El código para ConditionalFilterProvider se muestra a continuación:

using System.Web.Mvc;

public class ConditionalFilterProvider : IFilterProvider
{
    private readonly
      IEnumerable<Func<ControllerContext, ActionDescriptor, object>> _conditions;

    public ConditionalFilterProvider(
      IEnumerable<Func<ControllerContext, ActionDescriptor, object>> conditions)
    {
        _conditions = conditions;
    }

    public IEnumerable<Filter> GetFilters(
        ControllerContext controllerContext,
        ActionDescriptor actionDescriptor)
    {
        return from condition in _conditions
               select condition(controllerContext, actionDescriptor) into filter
               where filter != null
               select new Filter(filter, FilterScope.Global, null);
    }
}

Para WebAPI, estoy usando Mecanismo de protección CSRF de AngularJS, lo empaqueté con algunas clases de ayuda para una fácil implementación en el servidor, y estoy decorando los métodos API con un AuthorizeAttribute personalizado, como se describe aquí.

Todo esto funciona según lo previsto, pero me gustaría ir un paso más allá. Siguiendo el patrón usado para los controladores MVC, quiero crear un ConditionalFilterProvider que se pueda usar con los controladores WebAPI para poder asegurarme de que todos los métodos POST se decoren automáticamente con mi AuthorizeAttribute personalizado.

Sin embargo, aunque intenté crear un ConditionalFilterProvider para WebAPI, no estoy seguro de haberlo hecho bien y no puedo probarlo porque no sé cómo registrarlo. Lo que se me ha ocurrido es:

using System.Web.Http;

public class ConditionalApiFilterProvider : IFilterProvider
{
    private readonly
      IEnumerable<Func<HttpConfiguration, HttpActionDescriptor, object>> _conditions;

    public ConditionalApiFilterProvider(
      IEnumerable<Func<HttpConfiguration, HttpActionDescriptor, object>> conditions)
    {
        _conditions = conditions;
    }

    public IEnumerable<FilterInfo> GetFilters(
        HttpConfiguration configuration,
        HttpActionDescriptor actionDescriptor)
    {
        return from condition in _conditions
               select condition(configuration, actionDescriptor) into filter
               where filter != null
               select new FilterInfo(filter as IFilter, FilterScope.Action);
    }
}

Y para registrarlo en Application_Start (esto no funciona):

    private void ConfigureValidateCsrfHeaderAttribute()
    {
        //Configure a conditional filter
        string[] nonSafeMethods = { "post", "put", "delete" };
        IEnumerable<Func<HttpConfiguration, HttpActionDescriptor, object>> conditions =
            new Func<HttpConfiguration, HttpActionDescriptor, object>[] {
                    ( c, a ) => nonSafeMethods.Contains("need HTTP method here") ?
                    new ValidateCsrfHeaderAttribute() : null
            };

        var provider = new ConditionalApiFilterProvider(conditions);

        // This line adds the filter we created above
        FilterProviders.Providers.Add(provider);        //incorrect provider registration
    }

preguntado el 03 de diciembre de 13 a las 12:12

1 Respuestas

Descubrí cómo registrar un IFilterProvider personalizado para WebAPI, probé la solución y funciona correctamente. El código necesario para dar de alta al proveedor es:

using System.Web.Http;
using System.Web.Http.Filters;

private void ConfigureValidateCsrfHeaderAttribute()
{
    //Configure a conditional filter
    HttpMethod[] nonSafeMethods = { HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete };
    IEnumerable<Func<HttpConfiguration, HttpActionDescriptor, object>> conditions =
        new Func<HttpConfiguration, HttpActionDescriptor, object>[] {
                ( c, a ) => nonSafeMethods.Any(m => a.SupportedHttpMethods.Contains(m)) ?
                new ValidateCsrfHeaderAttribute() : null
    };

    var provider = new ConditionalApiFilterProvider(conditions);

    // This line adds the filter we created above
    GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider), provider);
}

Respondido el 03 de diciembre de 13 a las 15:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.