Reputation:
I would like to override the API Controller to check for certain values in the header on all HttpGet and HttpPost calls as they're made without including the code for the check in every single call. Currently my method looks like:
public class MyApiController : ApiController
{
[HttpGet]
public HttpResponseMessage GetAccountById()
{
var accountId = (Request.Headers.Where(t => t.Key == "accountid").Count() == 0) ? null : Request.Headers.GetValues("accountid").First();
var apiKey = (Request.Headers.Where(t => t.Key == "apikey").Count() == 0) ? null : Request.Headers.GetValues("apikey").First();
if (String.IsNullOrEmpty(accountId)) {
return Request.CreateResponse(HttpStatusCode.Forbidden, "Please provide an Account Id.");
}
if (String.IsNullOrEmpty(apiKey)) {
return Request.CreateResponse(HttpStatusCode.Forbidden, "Please provide an Account Api Key.");
}
// Get Account
// return Account;
}
}
How can I do that apikey/accountid check in every call without having to write the check into every call?
SOLUTION: Overriding the DelegatingHandler worked perfectly.
ApiSecurityHandler.cs
public class ApiSecurityHandler : DelegatingHandler
{
public ApiSecurityHandler(HttpConfiguration httpConfiguration)
{
InnerHandler = new HttpControllerDispatcher(httpConfiguration);
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var accountId = (request.Headers.Where(t => t.Key == "accountid").Count() == 0) ? null : request.Headers.GetValues("accountid").First();
var apiKey = (request.Headers.Where(t => t.Key == "apikey").Count() == 0) ? null : request.Headers.GetValues("apikey").First();
if (String.IsNullOrEmpty(accountId)) {
var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
response.Content = new StringContent("Please provide an Account Id.");
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response);
return tsc.Task;
}
if (String.IsNullOrEmpty(apiKey)) {
var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
response.Content = new StringContent("Please provide an Account Api Key.");
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response);
return tsc.Task;
}
// Authorize the Account Id and Api Key here
using (var accountManager = new AccountManager()) {
if (!accountManager.AuthorizeAccountApiKey(accountId, apiKey)) {
var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
response.Content = new StringContent("Api authorization denied.");
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response);
return tsc.Task;
}
}
return base.SendAsync(request, cancellationToken);
}
}
And the in your routing config just add this parameter to the map route:
handler: new ApiSecurityHandler(GlobalConfiguration.Configuration)
Upvotes: 1
Views: 3962
Reputation: 1333
I would recommend the use of DelegatingHandler.
This example from msdn show how to override your Header
This code should work, enjoy:
public class Myhandler: DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessagerequest, CancellationToken cancellationToken)
{
if(request.Headers.Contains("accountid") && request.Headers.Contains("apikey"))
{
string accountid = request.Headers.GetValues("accountid").FirstOrDefault();
string apikey = request.Headers.GetValues("apikey").FirstOrDefault();
//HERE you can get your account and do what you want
}else{
return SendError("please provide account id and api key", HttpStatusCode.Forbidden);
}
return base.SendAsync(request, cancellationToken);
}
private Task<HttpResponseMessage> SendError(string error, HttpStatusCode code)
{
var response = new HttpResponseMessage();
response.Content = new StringContent(error);
response.StatusCode = code;
return Task<HttpResponseMessage>.Factory.StartNew(() => response);
}
}
one more example of DelegatingHandler
Upvotes: 2
Reputation: 21440
What I would do, instead of overriding ApiController is, create a base class that inherits ApiController, and do your coding there. Like this:
public class APIBaseController : ApiController
{
[HttpGet]
public void APIBaseController() {
//Request.Headers.Count()
}
[HttpPost]
public void APIBaseController() {
//Request.Headers.Count()
}
}
And then do this:
public class MyApiController : APIBaseController
Upvotes: 0
Reputation: 120548
Write yourself a subclass of System.Web.Http.Filters.AuthorizationFilterAttribute
, with your own implementation of OnAuthorization
then you can use this attribute on individual controller methods or on the controller itself.
Here's an example of someone doing exactly this.
Upvotes: 1