如何在Asp.net MVC 5 ApiController中覆盖HttpGet / HttpPost

时间:2014-02-20 17:35:51

标签: c# asp.net asp.net-mvc api

我想覆盖API控制器,检查所有HttpGet和HttpPost调用中的标头中的某些值,而不是在每次调用时都包含检查代码。目前我的方法如下:

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

如何在每次通话时都进行apikey / accountid检查,而无需在每次通话中都写入支票?

解决方案:覆盖DelegatingHandler非常有效。

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

您的路由配置中只需将此参数添加到地图路线中:

handler: new ApiSecurityHandler(GlobalConfiguration.Configuration)

3 个答案:

答案 0 :(得分:1)

自己编写System.Web.Http.Filters.AuthorizationFilterAttribute的子类,使用自己的OnAuthorization实现,然后可以在单个控制器方法或控制器本身上使用此属性。

Here's an example某人正是这样做的。

答案 1 :(得分:1)

我建议使用DelegatingHandler。

This example from msdn显示如何覆盖您的标题

此代码应该有效,享受:

 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

More examples

答案 2 :(得分:0)

我会做什么,而不是重写ApiController,创建一个继承ApiController的基类,并在那里进行编码。像这样:

public class APIBaseController : ApiController
{
    [HttpGet]
    public void APIBaseController() {
        //Request.Headers.Count()
    }

    [HttpPost]
    public void APIBaseController() {
        //Request.Headers.Count()
    }
}

然后这样做:

public class MyApiController : APIBaseController