Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception : The given filter must implement one or more of the following filter interfaces when implementing custom filter in WebAPI 2

I am trying to build my custom filter for authentication, but I am running on this problem when I try to run my WebAPI solution:

The given filter instance must implement one or more of the following filter interfaces: System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter, System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter, System.Web.Mvc.Filters.IAuthenticationFilter.

The error occurs in FilterConfig class:

public class FilterConfig
{
   public static void RegisterGlobalFilters(GlobalFilterCollection filters)
   {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new AuthAttribute());
   }
}

In the line where I am trying to add AuthAttribute to filters.

This is whole AuthAttribute class:

using Examino.Business;
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IdentityModel;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;

namespace Examino.API.Filters
{
    public class AuthAttribute : AuthorizeAttribute
    {
        public ITokenProviderService TokenProviderService { get; set; }

        public override void OnAuthorization(HttpActionContext actionContext)
        {
            SetDependencies(actionContext);

            if (!IsAuthorized(actionContext) && !SkipAuthorization(actionContext))
            {
                if (Authenticate(actionContext) == AuthenticationErrors.UNAUTHORIZED)
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized,
                        new HttpResponseMessage(HttpStatusCode.Unauthorized));
                }
                else if (Authenticate(actionContext) == AuthenticationErrors.TOKEN_EXPIRED)
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized,
                        //token expired status code?
                        new HttpResponseMessage(HttpStatusCode.Unauthorized));
                }
            }
        }

        private void SetDependencies(HttpActionContext actionContext)
        {
            var requestScope = actionContext.Request.GetDependencyScope();

            if (TokenProviderService == null)
            {
                TokenProviderService = requestScope.GetService(typeof(ITokenProviderService)) as ITokenProviderService;
            }
        }

        private AuthenticationErrors Authenticate(HttpActionContext actionContext)
        {
            IEnumerable<string> authHeaderValues;
            actionContext.Request.Headers.TryGetValues("Authorization", out authHeaderValues);

            try
            {
                if (authHeaderValues != null)
                {
                    string bearerToken = authHeaderValues.ElementAt(0);
                    string token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;

                    Thread.CurrentPrincipal = TokenProviderService.ValidateJwtToken(token);
                    if (Thread.CurrentPrincipal != null)
                    {
                        return AuthenticationErrors.AUTHORIZED;
                    }
                }
            }
            catch (SecurityTokenExpiredException)
            {
                return AuthenticationErrors.TOKEN_EXPIRED;
            }
            catch (Exception)
            {
                return AuthenticationErrors.UNAUTHORIZED;
            }

            return AuthenticationErrors.UNAUTHORIZED;
        }

        private bool SkipAuthorization(HttpActionContext actionContext)
        {
            Contract.Assert(actionContext != null);

            return actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()
                || actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
        }

        private enum AuthenticationErrors
        {
            UNAUTHORIZED,
            TOKEN_EXPIRED,
            AUTHORIZED
        }
    }
}

As you can see it inherits from AuthorizeAttribute class.

Here is a stack trace:

[InvalidOperationException: The given filter instance must implement one or more of the following filter interfaces: System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter, System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter, System.Web.Mvc.Filters.IAuthenticationFilter.]
System.Web.Mvc.GlobalFilterCollection.ValidateFilterInstance(Object instance) +403
System.Web.Mvc.GlobalFilterCollection.AddInternal(Object filter, Nullable`1 order) +26
System.Web.Mvc.GlobalFilterCollection.Add(Object filter) +31
Examino.API.FilterConfig.RegisterGlobalFilters(GlobalFilterCollection filters) in C:\examino\src\Examino.API\App_Start\FilterConfig.cs:12
Examino.API.WebApiApplication.Application_Start() in C:\examino\src\Examino.API\Global.asax.cs:22

[HttpException (0x80004005): The given filter instance must implement one or more of the following filter interfaces: System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter, System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter, System.Web.Mvc.Filters.IAuthenticationFilter.]
System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) +540
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +186
System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +172
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +402
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +343

[HttpException (0x80004005): The given filter instance must implement one or more of the following filter interfaces: System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter, System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter, System.Web.Mvc.Filters.IAuthenticationFilter.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +539
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +125 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +731

Even if I implement for example IAuthenticationFilter interface same exception is thrown anyhow.

Did someone had a similar exception? I was unable to find something more about this in WebAPI.

like image 661
nemo_87 Avatar asked Sep 27 '16 06:09

nemo_87


1 Answers

Solved: The problem was place of registration of Filter. In MVC you would register filters in FilterConfing class, but in WebAPI you are doing this in Register method of WebApiConfig class like this:

config.Filters.Add(new AuthAttribute());

Everything works now.

like image 150
nemo_87 Avatar answered Oct 19 '22 12:10

nemo_87