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

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

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

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

提前致谢!

【问题讨论】:

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


    【解决方案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 没有任何作用。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-02-22
        • 2018-09-19
        • 2019-04-17
        • 2015-10-07
        • 2019-07-16
        • 2021-04-09
        • 1970-01-01
        相关资源
        最近更新 更多