【问题标题】:How to override HttpGet/HttpPost in Asp.net MVC 5 ApiController如何在 Asp.net MVC 5 ApiController 中覆盖 HttpGet/HttpPost
【发布时间】:2014-02-21 03:22:04
【问题描述】:

我想重写 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)

【问题讨论】:

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


    【解决方案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】:

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

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

      【讨论】:

        【解决方案3】:

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

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

        然后这样做:

        public class MyApiController : APIBaseController 
        

        【讨论】:

        • 嗯,是的。把那部分记下来了。需要在所有调用中覆盖 HttpGet 部分。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-30
        • 1970-01-01
        • 2013-11-29
        • 2011-10-01
        • 2013-10-15
        相关资源
        最近更新 更多