简体   繁体   English

WebAPI控制器忽略CORS

[英]WebAPI Controller Ignoring CORS

I have a WebAPI controller with a custom CORS policy provider attribute on the class. 我有一个WebAPI控制器,在该类上具有自定义CORS策略提供程序属性。 In defining the attribute, I have the following constructor. 在定义属性时,我有以下构造函数。

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class ConfiguredCORSPolicyProviderAttribute : ActionFilterAttribute, ICorsPolicyProvider
{
    private CorsPolicy _policy;

    public ConfiguredCORSPolicyProviderAttribute()
    {
        _policy = new CorsPolicy
        {
            AllowAnyMethod = true,
            AllowAnyHeader = true
        };

        // If there are no domains in the 'CORSDomainSection' section in Web.config, all origins will be allowed by default.
        var domains = (CORSDomainSection)ConfigurationManager.GetSection("CORSDomainSection");

        if (domains != null)
        {
            foreach (DomainConfigElement domain in domains.Domains)
            {
                _policy.Origins.Add(domain.Domain);
            }
        }
        else
        {
            _policy.AllowAnyOrigin = true;
        }
    }

    public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request)
    {
        return Task.FromResult(_policy);
    }

    public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken token)
    {
        return GetCorsPolicyAsync(request);
    }
}

The ConfigurationManager gets a list (from Web.config) of acceptable origins/domains that I want to allow to make requests. ConfigurationManager获取我希望允许发出请求的可接受来源/域的列表(来自Web.config)。

This code appropriately handles the "Access-Control-Allow-Origin" header, adding it when the request origin is on the list, and withholding it when not. 此代码适当地处理“Access-Control-Allow-Origin”标头,在请求源位于列表上时添加它,并在不存在时将其保留。 However, the code in the controller still gets called no matter what. 但是,无论如何,控制器中的代码仍会被调用。

Why, and how do I appropriately prevent the controller from executing if the origin of the request isn't allowed? 为什么,如果不允许请求的来源,如何适当地阻止控制器执行?


UPDATE || 更新 || [April 12, 2016 @ 12:30p] [2016年4月12日@ 12:30p]

I was able to resolve the issue using a combination of OnActionExecuted and OnActionExecuting method overrides, code below. 我能够使用OnActionExecutedOnActionExecuting方法覆盖的组合解决问题,下面的代码。

/// <summary>
/// Executed after the action method is invoked.
/// </summary>
/// <param name="context">The context of the HTTP request.</param>
public override void OnActionExecuted(HttpActionExecutedContext context)
{
    string requestOrigin;
    try
    {
        requestOrigin = context.Request.Headers.GetValues("Origin").FirstOrDefault();
    }
    catch
    {
        requestOrigin = string.Empty;
    }

    if (IsAllowedOrigin(requestOrigin))
    {
        context.Response.Headers.Add("Access-Control-Allow-Origin", requestOrigin);

        if (IsPreflight(context))
        {
            string allowedMethods = string.Empty;
            string allowedHeaders = string.Empty;

            if (Policy.AllowAnyMethod)
            {
                allowedMethods = context.Request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault();
            }
            else
            {
                foreach (var method in Policy.Methods)
                {
                    if (Policy.Methods.IndexOf(method) == 0)
                    {
                        allowedMethods = method;
                    }
                    else
                    {
                        allowedMethods += string.Format(", {0}", method);
                    }
                }
            }

            try
            {
                if (Policy.AllowAnyHeader)
                {
                    allowedHeaders = context.Request.Headers.GetValues("Access-Control-Request-Headers").FirstOrDefault();
                }
                else
                {
                    foreach (var header in Policy.Headers)
                    {
                        if (Policy.Headers.IndexOf(header) == 0)
                        {
                            allowedHeaders = header;
                        }
                        else
                        {
                            allowedHeaders += string.Format(", {0}", header);
                        }
                    }
                }

                context.Response.Headers.Add("Access-Control-Allow-Headers", allowedHeaders);
            }
            catch
            {
                // Do nothing.
            }

            context.Response.Headers.Add("Access-Control-Allow-Methods", allowedMethods);
        }
    }

    base.OnActionExecuted(context);
}

/// <summary>
/// Executed before the action method is invoked.
/// </summary>
/// <param name="context">The context of the HTTP request.</param>
public override void OnActionExecuting(HttpActionContext context)
{
    string requestOrigin;
    try
    {
        requestOrigin = context.Request.Headers.GetValues("Origin").FirstOrDefault();
    }
    catch
    {
        requestOrigin = string.Empty;
    }

    if (IsAllowedOrigin(requestOrigin))
    {
        base.OnActionExecuting(context);
    }
    else
    {
        context.ModelState.AddModelError("State", "The origin of the request is forbidden from making requests.");
        context.Response = context.Request.CreateErrorResponse(HttpStatusCode.Forbidden, context.ModelState);
    }
}

private bool IsAllowedOrigin(string requestOrigin)
{
    requestOrigin = requestOrigin.Replace("https://", "").Replace("http://", "");

    if (System.Diagnostics.Debugger.IsAttached || PolicyContains(requestOrigin))
    {
        return true;
    }
    else
    {
        return false;
    }
}

private bool PolicyContains(string requestOrigin)
{
    foreach (var domain in _policy.Origins)
    {
        if (domain.Replace("https://", "").Replace("http://", "") == requestOrigin)
        {
            return true;
        }
    }

    return false;
}

private bool IsPreflight(HttpActionExecutedContext context)
{
    string header = string.Empty;

    try
    {
        header = context.Request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault();
    }
    catch
    {
        return false;
    }

    if (header != null && context.Request.Method == HttpMethod.Options)
    {
        return true;
    }
    else
    {
        return false;
    }
}

CORS headers are not expected to prevent calls to controller - ie if native client (pretty much anything that is not a browser) calls the method it should be handled by default. CORS头文件不会阻止对控制器的调用 - 即如果本机客户端(几乎任何不是浏览器的东西)调用该方法,则默认情况下应该处理它。

If you really need to block such calls - perform similar checks in before controller get called in OnActionExecutingAsync . 如果您确实需要阻止此类调用 - 在OnActionExecutingAsync调用控制器之前执行类似的检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM