【问题标题】:ASP.NET WebApi - Enable CORS for multiple OriginsASP.NET WebApi - 为多个来源启用 CORS
【发布时间】:2017-02-22 23:58:21
【问题描述】:

我一直在尝试为我的 API 启用多个来源的 CORS,但没有成功。

这是我所做的。

创建了 CORS 策略

 [AttributeUsage(AttributeTargets.All, AllowMultiple =false, Inherited =true)]
    public class TCCorsPolicyProvider : Attribute, ICorsPolicyProvider
    {
        private CorsPolicy _policy;

        public TCCorsPolicyProvider()
        {
            _policy = new CorsPolicy
            {
                SupportsCredentials = true
            };
            string[] allowedOrigins = "john.doe,ava.wise".Split(',');
            string[] allowedMethods = "GET,POST,PUT,OPTIONS".Split(',');
            string[] allowedHeaders = "Content-Type,Origin,Authorization,Accept".Split(',');
            // Add allowed origins.
            foreach (string origin in allowedOrigins)
                _policy.Origins.Add(origin);
            foreach (string method in allowedMethods)
                _policy.Methods.Add(method);
            foreach (string header in allowedHeaders)
                _policy.Headers.Add(header);
        }

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

创建工厂

public class TCCorsPolicyProviderFactory : ICorsPolicyProviderFactory
    {
        ICorsPolicyProvider _provider;
        public TCCorsPolicyProviderFactory()
        {
            _provider = new TCCorsPolicyProvider();
        }
        public ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
        {
            return _provider;
        }
    }

在 WebApiConfig.cs 类中启用 Cors

config.SetCorsPolicyProviderFactory(new TCCorsPolicyProviderFactory());
            config.EnableCors();

确保在 Global.asax Application_Start 中进行了适当的注册

 GlobalConfiguration.Configure(WebApiConfig.Register);

当上述方法不起作用时,我什至手动将策略属性应用于所有其他控制器继承的基本控制器

[TCCorsPolicyProvider]
    public class BaseApiController : ApiController
    {
        public string IpAddress
        {
            get { return ContextHelper.GetIpAddress(); }
        }

        private bool _disposed;
        protected virtual void Dispose(bool disposing, Action disposeAction)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    disposeAction();
                }
            }
            _disposed = true;
        }
    }

但我收到以下错误(Invoking Api from Angular)

XMLHttpRequest 无法加载 hqidwtcdwa01/api/localizations/reloadCache。 请求中不存在“Access-Control-Allow-Origin”标头 资源。因此,Origin 'ava.wise' 不允许访问。这 响应的 HTTP 状态代码为 401。

hqidwtcdwa01 是目的地,ava.wise 是起点。

到目前为止,我发现 xmlhttp 响应中的 http 响应标头不包含 Access-Control-Allow-Origin。但是,当我使用 HttpCient 时,我可以看到标题。

【问题讨论】:

    标签: .net angularjs asp.net-web-api cors


    【解决方案1】:

    我相信 cors 理论上允许多个来源,但实际上不允许。对于我的站点,我创建了一个新的 CORS 属性并根据传入返回一个允许的来源,这比使用 *

     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
                AllowMultiple = false)]
    public class GlobalEnableCorsAttribute :
    
    
     Attribute, ICorsPolicyProvider
        {
            public Boolean SupportsCredentials = true;
            public CorsHandler handle = new CorsHandler();
            public async Task<CorsPolicy> GetCorsPolicyAsync(
              HttpRequestMessage request, CancellationToken cancellationToken)
            {
                 var corsRequestContext = request.GetCorsRequestContext();
                var originRequested = corsRequestContext.Origin;
    
    
                string approvedOrigin = handle.approveCorsOrigin(originRequested);
    
                if(!string.IsNullOrEmpty(approvedOrigin))
                {
                    // Grant CORS request
                    var policy = new CorsPolicy
                    {
                        AllowAnyHeader = true,
                        AllowAnyMethod = true,
                        SupportsCredentials = true
                    };
    
                    // add headers
                    policy.Headers.Add("content-type");
                    policy.Headers.Add("withcredentials");
                    policy.Headers.Add("Access-Control-Allow-Headers");
                    policy.Headers.Add("Access-Control-Allow-Origin");
                    policy.Headers.Add("Origin");
                    policy.Headers.Add("Accept");
                    policy.Headers.Add("X-Requested-With");
                    policy.Headers.Add("Access-Control-Request-Method");
                    policy.Headers.Add("Access - Control - Request - Headers");
    
    
                    policy.Origins.Add(approvedOrigin);
                    return policy;
                }
                else
                {
                    // Reject CORS request
                    return null;
                }
            }
    
    
    
        }
    

    来源搜索从服务器配置值中获取允许的来源

     public class CorsHandler
    {
        public string approveCorsOrigin(string providedOrigin)
        {
            // load list of web.config origins
            string fullList = Properties.Settings.Default.CORSOriginPermittedSite;
    
            if (!string.IsNullOrEmpty(fullList))
            {
                string[] originArray = fullList.Split(new char[]{ ','}, StringSplitOptions.RemoveEmptyEntries);
    
                foreach(string approvedOrigin in originArray)
                {
                    if (providedOrigin.Trim() == approvedOrigin.Trim())
                    {
                        return providedOrigin;
                    }
                }
            }
            return null;
        }
    }
    

    用法如下

     public static void Register(HttpConfiguration config)
        {
            if (Properties.Settings.Default.CORSOriginPermittedSite != null && !string.IsNullOrWhiteSpace(Properties.Settings.Default.CORSOriginPermittedSite))
            {
                var cors = new GlobalEnableCorsAttribute();
                config.EnableCors(cors);
            }
        }
    

    最后,这段代码是针对 webapi 设置的,但应该具有可比性,而且您(如果使用类似的话)还需要在飞行前处理同源搜索。..

    【讨论】:

      【解决方案2】:

      我在使用 owincontext 构建 mvc api 时遇到了非常相似的问题,我必须添加

      #if DEBUG //Notice this is only when I'm in debug mode.
       context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
      #endif
      

      但是,当我部署特定于所需来源的添加标头时。 而且由于您的错误相似,它可能有助于添加 Access-Control-Allow-Origin : ava.wise 标头并检查它是否解决。希望它有助于缩小您的问题。

      您希望在标题中包含的示例,注意 Options 方法将接受的来源获取到任何“*”。

      ---更新---

      请尝试更新 web.config 添加标题。 Custom Headers 这应该反映在响应中。显然,这在代码中是可能的,但从简单开始。

       <configuration>   <system.webServer>
        <httpProtocol>
           <customHeaders>
              <remove name="Access-Control-Allow-Origin" />
              <add name="Access-Control-Allow-Origin" value="*" />
           </customHeaders>
        </httpProtocol>   
       </system.webServer>
      </configuration>
      

      【讨论】:

      • 响应中显然没有添加标头。可能是什么原因造成的?
      • 所以我认为标题的所有其他部分都按照您在策略中的设置正确设置。正确的?我已经更新了答案,以显示您可以在哪里尝试添加提到的标题。您是否能够显示 OPTIONS 方法返回的内容、飞行前请求、屏幕截图? [启用 Cors] (asp.net/web-api/overview/security/…) 如果您还没有尝试过。
      • 配置有效,事实上就是这样。但是我需要切换到代码,因为我不需要将多个来源添加到允许列表中。
      • Hmmmm...尝试完全注释标题添加部分并添加_policy.AllowAnyHeader = true;只是为了确保您添加的标题与您添加的来源不矛盾..
      • 好吧,所以我使用 HttpClient 向我的 API 发出请求(在通过代码启用 CORS 之后)。我看到响应具有适当的标头。奇怪的是浏览器无法看到标题。有什么想法吗?
      【解决方案3】:

      我以一种肮脏而艰难的方式做到了,也许不是那么建议,但这让我继续前进(假设你安装了 cors nuget、web api 2.0 和 .NET 4.5):

      web.config:

      <appSettings>
          <add key="AllowedDomains" value="http://domain0:8009, http://domain1:8009"/>
       </appSettings>
      

      Configs.cs:

      public static string AllowedDomains {
              get {
                  return @ConfigurationManager.AppSettings["AllowedDomains"].ToString();
              }
          }
      

      WebApiConfig:

          public static void Register(HttpConfiguration config)
          {
              var attribute = new System.Web.Http.Cors.EnableCorsAttribute(Configs.AllowedDomains, "*", "*"); //domains, headers, methods - you could do the same for the other args.
              config.EnableCors(attribute); //global
          }
      

      要按控制器/动作过滤,只需在顶部添加属性:

      [System.Web.Http.Cors.EnableCors(origins: "http://domain2:8009", headers: "*", methods: "*")]
      

      让我知道任何进展或 cmets。希望这可以帮助。谢谢! :)

      【讨论】:

        猜你喜欢
        • 2015-09-25
        • 2021-04-09
        • 2016-07-18
        • 2021-12-30
        • 2020-09-07
        • 2015-11-28
        • 1970-01-01
        • 2021-11-11
        相关资源
        最近更新 更多