4111

WebApi Authorization Filter

Question:

I have a web api authorization filter that is applied to the base controller of a web api controller. Authorization type is Basic. The authorization filter is using the IAutofacAuthenticationFilter and is using some autofac injected services to perform authorization and authentication.

Everything works as expected on GET requests. The authorization header is read and confirmed and in case the request does not have the proper authorization information in the authorization header the request is responded to using.

public void OnChallenge(HttpAuthenticationChallengeContext context) { var host = context.Request.RequestUri.DnsSafeHost; context.Request.CreateResponse(HttpStatusCode.Unauthorized, "Unauthenticated request"); context.Request.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", host)); }

However, when a POST request is made, everything is called the same way and the above method gets called as expected, but the request keeps on processing by going to the actual controller action.

OnAuthorization is not modified or overloaded. Instead,

OnAuthenticate looks like this:

public void OnAuthenticate(HttpAuthenticationContext context) { var identity = ParseAuthorizationHeader(context.ActionContext); // identity is a custom object representing the information in the auth header if (identity == null) { HandleUnauthorizedRequest(context.ActionContext); return; } if (!OnAuthorizeUser(identity.Name, identity.Key, context.ActionContext)) { HandleUnauthorizedRequest(context.ActionContext); return; } }

Here is a custom method to set the principal and authenticate the user:

protected virtual bool OnAuthorizeUser(KeyContainer name, string key, HttpActionContext actionContext) { // get principal code ... Thread.CurrentPrincipal = principal; actionContext.RequestContext.Principal = principal; if (HttpContext.Current != null) HttpContext.Current.User = principal; return true; }

The authorization filter is registered with the container with the following:

builder.Register(c => new AuthorizeActionFilterAttribute( c.Resolve<IService>()) .AsWebApiAuthenticationFilterFor<BaseApiController>() .InstancePerRequest();

What's happening in a POST request that is different than the GET one and how can this be fixed?

Answer1:

I am guessing that the problem is with the InstancePerRequest registration of the filter. We have a <a href="http://autofac.readthedocs.org/en/latest/faq/per-request-scope.html" rel="nofollow">fairly extensive FAQ on per-request scope usage</a> and part of that notes that <a href="http://autofac.readthedocs.org/en/latest/faq/per-request-scope.html#no-per-request-filter-dependencies-in-web-api" rel="nofollow">you can't have per-request dependencies in filters</a> because WebAPI caches filter instances for controllers once they're created - the only way to successfully make that work (as you've discovered) is to use service location from within the filter itself. Unfortunately there's nothing we can do from an Autofac side; it's all built-in and not-overridable in WebAPI to behave that way.

Hopefully they'll change that in ASP.NET vNext.

Recommend

  • ASP.NET MVC Controller cannot return HttpResponseMessage correctly with streamed content
  • How to switch between two luis.ai dialog with different languages
  • Is it correct to use Post instead of Get to fetch data in Web API
  • How to pass a pdf from WebAPI and read the pdf from the MVC Controller?
  • Generic interface problem
  • DELETE verb working in Postman but not with ajax
  • Azure Functions - can't be invoked from Azure WebJobs SDK
  • Selenium ChromeDriver (C#) Crashes Only in Visual Studio Debug Mode
  • JAX-RS Rest services stopped deploying on Eclipse Glassfish
  • Java EE 6 Login module
  • Realm, query for objects in realm using swift
  • Office365 authentication without login redirection
  • Symfony2 plaintext users don't work
  • ASP.NET windows authentication should always ask for credentials
  • Authentication failed with Azure Active Directory in Windows Phone
  • Optimizing database types to compact database (SQLite)
  • Cross-Platform Protobuf Serialization
  • script to move all files from one location to another location
  • Font Awesome Showing Box instead of Icons
  • Do I've to free mysql result after storing it?
  • Properly structure and highlight a GtkPopoverMenu using PyGObject
  • Why winpcap requires both .lib and .dll to run?
  • AT Commands to Send SMS not working in Windows 8.1
  • Windows forms listbox.selecteditem displaying “System.Data.DataRowView” instead of actual value
  • AngularJs get employee from factory
  • Free memory of cv::Mat loaded using FileStorage API
  • How to set the response of a form post action to a iframe source?
  • Angular 2 constructor injection vs direct access
  • Memory offsets in inline assembly
  • Java static initializers and reflection
  • Android Google Maps API OnLocationChanged only called once
  • Turn off referential integrity in Derby? is it possible?
  • apache spark aggregate function using min value
  • Are Kotlin's Float, Int etc optimised to built-in types in the JVM? [duplicate]
  • Is it possible to post an object from jquery to bottle.py?
  • unknown Exception android
  • Sorting a 2D array using the second column C++
  • UserPrincipal.Current returns apppool on IIS
  • Python/Django TangoWithDjango Models and Databases
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize