WebAPI - 为子域启用CORS

时间:2016-03-30 11:47:39

标签: c# asp.net-web-api cors

我希望使用以下标准为web-api应用程序启用CORS:

  1. 允许同一网站使用HTTPS或HTTP
  2. 忽略SUBDOMAIN - 含义mysite.comwww.mysite.com相同
  3. 我想以优雅的方式为多个网站执行此操作,而不是将所有排列设置为以逗号分隔。

    提前致谢!

4 个答案:

答案 0 :(得分:4)

除了明确指定所有排列之外,我能想到的唯一方法是实现自定义CORS策略

您可以详细了解here

答案 1 :(得分:3)

你走了。

如果需要任何修订或错误修复,请添加Git gist

public class WildcardOriginCorsPolicy : Attribute, ICorsPolicyProvider
    {
        private readonly string _origins;
        private readonly string _headers;
        private readonly string _methods;

        //private readonly CorsPolicy _policy;
        //
        // Summary:
        //     Initializes a new instance of the WildcardOriginCorsPolicy class.
        //
        // Parameters:
        //   origins:
        //     Comma-separated list of origins that are allowed to access the resource. Use
        //     "*" to allow all.
        //     "*.example.com" for subdomains
        //
        //   headers:
        //     Comma-separated list of headers that are supported by the resource. Use "*" to
        //     allow all. Use null or empty string to allow none.
        //
        //   methods:
        //     Comma-separated list of methods that are supported by the resource. Use "*" to
        //     allow all. Use null or empty string to allow none.
        public WildcardOriginCorsPolicy(string origins, string headers, string methods)
        {
            this._origins = origins;
            this._headers = headers;
            this._methods = methods;
        }

        public bool SupportsCredentials { get; set; }

        public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var policy = CreatePolicy(request.GetCorsRequestContext(), this._origins, this._headers, this._methods);
            policy.SupportsCredentials = this.SupportsCredentials;

            return Task.FromResult(policy);
        }

        private static CorsPolicy CreatePolicy(CorsRequestContext requestContext, string origins, string headers, string methods)
        {

            var corsPolicy = new CorsPolicy();
            if (origins == "*")
            {
                corsPolicy.AllowAnyOrigin = true;
            }
            else
            {
                var originsStringArray = origins.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                var requestOrigin = requestContext.Origin.ToLowerInvariant();

                foreach (var originItem in originsStringArray)
                {
                    ////Check if the current request uri matches with any of the wildcard origins.
                    if (Regex.IsMatch(requestOrigin, WildCardToRegularExpression(originItem)))
                    {
                        corsPolicy.Origins.Add(requestOrigin);
                    }
                }
            }

            if (!String.IsNullOrEmpty(headers))
            {
                if (headers == "*")
                {
                    corsPolicy.AllowAnyHeader = true;
                }
                else
                {
                    var headersStringArray = headers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    corsPolicy.Headers.AddAll(headersStringArray);
                }
            }

            if (!String.IsNullOrEmpty(methods))
            {
                if (methods == "*")
                {
                    corsPolicy.AllowAnyMethod = true;
                }
                else
                {
                    var methodsStringArray = methods.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    corsPolicy.Methods.AddAll(methodsStringArray);
                }
            }

            return corsPolicy;
        }

        private static string WildCardToRegularExpression(String value)
        {
            return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
        }
    }

像这样使用它。

var cors = new WildcardOriginCorsPolicy("*.example.com,http://localhost:*", "*", "POST,PUT,DELETE,GET,OPTIONS") { SupportsCredentials = true };
config.EnableCors(cors);

答案 2 :(得分:2)

您可以在没有通配符的情况下为 * .mydomain.com 实施此动态。您可以参考以下方法(自定义CORS策略提供程序

public class MyCorsPolicy : Attribute, ICorsPolicyProvider
    {
        public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var policy = new CorsPolicy();
            var requestUri = request.RequestUri;
            var authority = requestUri.Authority.ToLowerInvariant();
            if (authority.EndsWith(".mydomain.com") || authority == "mydomain.com")
            {
                // returns a url with scheme, host and port(if different than 80/443) without any path or querystring
                var origin = requestUri.GetComponents(System.UriComponents.SchemeAndServer, System.UriFormat.SafeUnescaped);
                policy.Origins.Add(origin);
            }

            return Task.FromResult(policy);
        }
    }


    [MyCorsPolicy]
    public class TestController : ApiController
    {
    }

正如其他帖子中已经提到的,您可以访问网址https://msdn.microsoft.com/en-us/magazine/dn532203.aspx以获取有关自定义CORS策略提供商的更多信息

答案 3 :(得分:0)

干净的端到端实现

CORSpolicy.cs

    using System;
    using System.Configuration;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Cors;
    using System.Web.Http.Cors;

    public class CORSPolicy : Attribute, ICorsPolicyProvider
    {
        public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            CorsPolicy policy = null;

            var corsRequestContext = request.GetCorsRequestContext();
            var originRequested = corsRequestContext.Origin;

            if (IsAValiOriginFrom(originRequested))
            {
                policy = new CorsPolicy
                {
                    AllowAnyHeader = true,
                    AllowAnyMethod = true,
                };

                policy.Origins.Add(originRequested);
            }

            return Task.FromResult(policy);
        }

        private bool IsAValiOriginFrom(string origin)
        {
            var isValid = false;
            var corsAllowed = ConfigurationManager.AppSettings["CORSDomains"].Split(',');

            foreach (var cor in corsAllowed)
            {
                if (origin.EndsWith(cor, StringComparison.InvariantCultureIgnoreCase))
                {
                    isValid = true;
                    break;
                }
            }

            return isValid;
        }
    }

TestController.cs

    using System;
    using System.Web.Http;

    [CORSPolicy]
    [RoutePrefix("api/v1/Test")]
    public class TestController : ApiController
    {
        // GET: api/v1/Test/123
        [HttpGet]
        [Route("{clientId}")]
        public string Get(int clientId)
        {
            return "123456";
        }
    }

Web.config

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <appSettings>
            <add key="CORSDomains" value="test.net,example.com" />
        </appSettings>
    </configuration>