I’m currently developing an WCF4 based REST webservice. Most calls don’t need authorization, but some do, so my plan is to implement an RequireAuthorization attribute that handles API key authorization for some calls.
After reading Implementing an Authorization Attribute for WCF Web API I implemented an HttpOperationHandler that handles the API key validation in the OnHandle method and added it to the RequestHandlers in the service configuration.
Basically this works fine, but I need to pass the user info I extracted in the AuthOperationHandler to the service, but I can’t find any information on this.
Can anyone help?
public class ServiceConfiguration : WebApiConfiguration
{
public ServiceConfiguration()
{
RequestHandlers = (c, e, od) => {
var authorizeAttribute = od.Attributes.OfType<RequireAuthorizationAttribute>().FirstOrDefault();
if (authorizeAttribute != null)
{
c.Add(new AuthOperationHandler(authorizeAttribute));
}
};
CreateInstance = (serviceType, context, request) => RepositoryFactory.GetInstance(serviceType);
}
}
public class AuthOperationHandler : HttpOperationHandler<HttpRequestMessage, HttpRequestMessage>
{
protected override HttpRequestMessage OnHandle(HttpRequestMessage input)
{
// API Key validation here
var user = RetrieveUserByApiKey(input);
return input;
}
}
I found a solution to this, but it does come with a caveat.
The way I did it was for my operation handler to return some form of custom authentication state class instead of a HttpResponsemessage – in my case I used an AuthenticationTicket.
And the AuthenticationTicket class just stores the account ID.
Then in your service method you add an AuthenticationTicket as a parameter and this will be populated for you by the operation handler.
You can then use the ticket in your method implementation.
However, this acts a bit funny with POST, PUT and DELETE operations if you need to use an additional parameter, like so:
You’ll get an exception along the following lines:
The solution I found (not sure whether it’s right) is to wrap the resource in a HttpRequestMessage like so:
Then in your method use the following to retrieve the Person:
Hope this helps, it works for me. But I’m still learning myself to be honest, so there may be better ways of doing it.