As I see I have 3 possible places to plug my stuff in the pipeline
1) AuthorizationFilters 2) Action Filters 3) DelegatingHandler
The most obvious one is AuthorizationFilters , where I can decorate my actions/ controllers with my custom authorization attribute . say .. MyCustomAuthorizationAttribute
.
Since HTTP message handlers are in the first stage in the processing pipeline. Does it make any sense to put it in there ?
Authorization for me right now simply means checking a token in the header which is given to the client after authentication.
You can place the Authorize attribute on a controller or on individual actions inside the controller. When we place the Authorize attribute on the controller itself, the authorize attribute applies to all of the actions inside.
Web API assumes that authentication happens in the host. For web-hosting, the host is IIS, which uses HTTP modules for authentication. You can configure your project to use any of the authentication modules built in to IIS or ASP.NET, or write your own HTTP module to perform custom authentication.
When your application requests private data, the request must be authorized by an authenticated user who has access to that data. When your application requests public data, the request doesn't need to be authorized, but does need to be accompanied by an identifier, such as an API key.
Update July 2014
My original answer covered WebApi 1. with WebApi 2 there were some changes i.e. there is now an IAuthenticationFilter
meaning you can move authentication logic out of the DelegatingHandler
which is a little more elegant.
There is a Nuget project here that offers an implementation of IAuthenticationFilter and also explains some background to its introduction.
OWIN middleware is now perhaps the best place to implement your authentication logic - there is an example of Certificate Authentication here and Basic Authentication OWIN Middleware here in this blog post the former example is the preferred one as it demonstrates the use of the base AuthenticationHandler
class.
The advice on AuthorizationFilters
remains largely unchanged.
End Update
Typically...
Use DelegatingHandler
to carry out Authentication... i.e. who someone is. Use this to set the Principle of the Thread and User context, add claims etc. You can place authorisation logic here too but on a fairly global scale. I would personally always use AuthorizationFilters for authorisation.
Use AuthorizationFilters
to restrict controllers and actions to specific people. These are used when you can extrapolate their permission with the information in claims, principal, url or the http request parameters. The default authorisation filter can be used to restrict access to anonymous users or by roles (if set in something like a delegating handler) - obviously you can implement your own AuthorizationFilters too if you need it.
Occasionally use ActionFilters
when you need to make the decision over authorisation using the message content e.g. you need access to a property on the entity to decide whether they have access (obviously be careful with this(!)).
Note:
The AuthorizationFilters
are called before the content of the body is read therefore they do not have access to the message body to make authorization decisions this is why the ActionFilters
specifically the OnActionExecuting
is used to occasional raise authentication errors.
So
In your scenario I would put a simple DelegatingHandler
to take your header and set the principal.
public class CustomAuthenticationMessageHandler : DelegatingHandler { public CustomAuthenticationMessageHandler () { } protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { Authenticate(request); return base.SendAsync(request, cancellationToken); } protected virtual void Authenticate(HttpRequestMessage request) { var authorisationHeader = request.Headers.Authorization; if (authorisationHeader == null) { return; } //Ensure you are happy with the header contents then { var principal = new GenericPrincipal(//new Identity , //Roles); Thread.CurrentPrincipal = principal; HttpContext.Current.User = principal; } } }
Then use AuthorizationFilters
to restrict access:
[Authorize] public string Get() { } [Authorize(Roles = "Admin")] public string GetAdminOnly() { }
To register the global Authentication
config.MessageHandlers.Add(new CustomAuthenticationMessageHandler());
This will mean that in every request the principal will be set to either null or a valid identity. It won't handle authorisation i.e. wont deny access to any controllers or actions.
To start protecting resources
Either target protected controllers and actions with the standard or custom [Authorize] attributes. Or register globally:
config.Filters.Add(new AuthorizeAttribute());
And only white list the controllers and actions you want unsecured using the [AllowAnonymous]
attribute.
If you only want authentication on some routes
Then you can modify your DelegatingHandler
a little to set the InnerHandler
to route to the correct controller e.g.
public CustomAuthenticationMessageHandler(HttpConfiguration configuration) { InnerHandler = new HttpRoutingDispatcher(configuration); }
And then you can specify this handler on your routes like so:
config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "myurl", defaults: new {}, constraints: new {}, handler: new CustomAuthenticationHandler(config) );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With