WebAPI - 为子域启用 CORS

Posted

技术标签:

【中文标题】WebAPI - 为子域启用 CORS【英文标题】:WebAPI - Enable CORS for Subdomains 【发布时间】:2016-07-18 09:38:54 【问题描述】:

我想为具有以下条件的 web-api 应用程序启用 CORS:

    允许同一站点使用 HTTPS 或 HTTP 忽略子域 - 含义 mysite.comwww.mysite.com 相同

我想以一种优雅的方式为多个站点执行此操作,而不是将所有排列都以逗号分隔。

提前致谢!

【问题讨论】:

【参考方案1】:

干净的端到端实施

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>

【讨论】:

【参考方案2】:

给你。

如果需要任何修订或错误修复,请添加 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);

【讨论】:

【参考方案3】:

您可以在不使用通配符的情况下为 *.mydomain.com 实现此动态。您可以参考以下方法(Custom CORS Policy Providers

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
    
    

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

【讨论】:

我无法让它工作,request.RequestUri 公开了“目标”域,而不是我的请求来自哪里。 request.GetCorsRequestContext() 将提供请求的实际来源。【参考方案4】:

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

您可以阅读更多关于它的信息here。

【讨论】:

正是我想要的。我应该考虑构建一个自定义的自定义属性。谢谢! 如果我在 EnableCors attribute it works, as soon as I add mysite/subsite 中使用 http://mysite,那么 API 没有任何作用。

以上是关于WebAPI - 为子域启用 CORS的主要内容,如果未能解决你的问题,请参考以下文章

如何单独为子域名启用 SSL,即使用 HTTPS 访问

带有 AngularJS CORS 的 IE9、IE8 返回“访问被拒绝” - ASP.NET WebApi

ASP.NET WebApi - 为多个来源启用 CORS

Lync Server子域启用Lync功能

如何使用 GKE 启用子域

使用Azure功能启用CORS通配符子域