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)
);