Web API 2 - 阻止所有外部调用

Posted

技术标签:

【中文标题】Web API 2 - 阻止所有外部调用【英文标题】:Web API 2 - block all external calls 【发布时间】:2014-09-27 17:16:09 【问题描述】:

是否可以阻止对我的 web api 的所有不是来自网站本身的调用?

我的意思是,如果我的 MVC 应用程序运行在:http://www.domain.com 并且 web api 运行在 http://www.domain.com/api/service,我希望 web api 只接受来自当前应用程序的调用。不允许外部调用。

我猜在这种情况下消息处理程序可能是最好的?

【问题讨论】:

你读过cors吗? en.wikipedia.org/wiki/Cross-origin_resource_sharing CORS 用于告诉浏览器跨源请求应该来自哪里,由客户端决定是否强制执行 CORS。 【参考方案1】:

为错误页面创建一个控制器并像这样捕获所有垃圾请求:

 config.Routes.MapHttpRoute("block", "*something", new  controller = "Error", action = "Get" );

【讨论】:

【参考方案2】:

您应该使用委托处理程序来实现令牌授权。

 public class AuthorizationHeaderHandler : DelegatingHandler

    public AuthorizationHeaderHandler(HttpConfiguration httpConfiguration)
    

        //set the inner handler
        InnerHandler = new HttpControllerDispatcher(httpConfiguration); 
    

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    
        IEnumerable<string> apiKeyHeaderValues = null;

        if (request.Headers.TryGetValues("X-ApiKey", out apiKeyHeaderValues))
        
            var apiKeyHeaderValue = apiKeyHeaderValues.First();

            //based on the api-key get username whose session is stil valid.

            var username = //code to get user based on apiKeyHeaderValue;

            if (!string.IsNullOrEmpty(username))
            
                var usernameClaim = new Claim(ClaimTypes.Name, username);
                var identity = new ClaimsIdentity(new[] usernameClaim, "ApiKey");
                var principal = new ClaimsPrincipal(identity);

                Thread.CurrentPrincipal = principal;
            

        
        else
        
            //You don't have an ApiKey from the request... can't proceed
            var response = request.CreateResponse(HttpStatusCode.Forbidden,
                new Message = "You are not Authorized to access that resource"); //new HttpResponseMessage(HttpStatusCode.Forbidden);
            var tsc = new TaskCompletionSource<HttpResponseMessage>();
            tsc.SetResult(response);
            return tsc.Task;
        

        return base.SendAsync(request, cancellationToken);
    

然后您可以在 WebApiConfig 中注册处理程序

 public class WebApiConfig

    public static void Init(HttpConfiguration config)
    

        config.Routes.MapHttpRoute(
           name: "DefaultApi",
           routeTemplate: "api/controller/action/id",
           defaults: new  id = RouteParameter.Optional ,
           constraints:null,
           handler: new AuthorizationHeaderHandler(GlobalConfiguration.Configuration)
       );


    

然后你可以设置你的登录控制器来授权用户并分配一个令牌

public class UserController : ApiController




    public async Task<HttpResponseMessage> Login([FromBody] UserDTO userDTO)
    
        // first perform user authentication.

        // clear all existing tokens for this  authorized user


        //create security token and save token of current user
        //You can store this in a database and use a repository to create these.
        // Tokens can be guids.  
        // await token creation

        return Request.CreateResponse(HttpStatusCode.OK, new LogingResult = result, token = token);
    

一旦该用户拥有令牌,就可以通过添加到请求标头来将其用于 Api 请求。在 Angularjs 中,它可以采用以下形式。

'use strict';

(函数()

angular.module('App', ['ngRoute', 'ngCookies']);

//interceptor for server calls

var httpInterceptor = function ($q, $window, $location) 
    return function(promise) 
        var success = function(response) 
            return response;
        ;

        var error = function(response) 
            if (response.status === 403) 
                $location.url('/login');
            

            return $q.reject(response);
        ;

        return promise.then(success, error);
    ;



httpInterceptor['$inject'] = ['$q', '$window', '$location'];
angular.module('App').factory('httpInterceptor', httpInterceptor);



var api = function ($http, $cookies) 
    return 
        init: function (token) 
            $http.defaults.headers.common['X-ApiKey'] = token || $cookies.token;
        
    ;


api['$inject'] = ['$http', '$cookies'];

angular.module('App').factory('api',  api);

)();

【讨论】:

【参考方案3】:

是的,这绝对是可能的。您必须为请求中找到的 RemoteIpAddress 创建自定义处理程序和过滤器。这是使用 Owin Self-Host 的实现:

 public class CustomerHandler : DelegatingHandler

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    
        if (request?.GetClientIpAddress() != "127.0.0.1")
        
            return await Task.FromResult(request.CreateResponse(HttpStatusCode.Unauthorized));
        

        return await base.SendAsync(request, cancellationToken);
    


public static class HttpReqestMessageExtension

    public static string GetClientIpAddress(this HttpRequestMessage request)
    
        if (!request.Properties.ContainsKey("MS_OwinContext")) return null;

        dynamic owinContext = request.Properties["MS_OwinContext"];
        return owinContext.Request.RemoteIpAddress;
    


如果您使用 ASP.Net,那么您将使用适当的键 => MS_HttpContext

现在您只需将其添加到您的 Api 的启动中:

var config = new HttpConfiguration();
config.MessageHandlers.Add(new CustomerHandler());

【讨论】:

以上是关于Web API 2 - 阻止所有外部调用的主要内容,如果未能解决你的问题,请参考以下文章

为啥我对 web.api 的请求被长时间运行的控制器代码阻止?

如何阻止对 Web API 的 hack/DOS 攻击

从 Web API 同步调用外部 api

从 Web Api 调用 Graph Api 不会返回所有用户数据

来自 ASP NET Web API 的 CORS 阻止 Ajax POST 调用 - 对预检请求的响应未通过访问控制检查

如果 EnableCors Origin 无效,则完全阻止 Web API 执行