在 Azure Web 应用/Azure API 上部署时缺少 CORS 标头

Posted

技术标签:

【中文标题】在 Azure Web 应用/Azure API 上部署时缺少 CORS 标头【英文标题】:CORS headers missing when deployed on Azure Web App / Azure API 【发布时间】:2016-08-13 00:00:00 【问题描述】:

我创建了一个 OWIN 托管 WebAPI 2。还有一个使用 API 并充当客户端的网络应用 (AngularJS)。

我已将CORS 的必要代码添加到Startup.cs,并将其托管在与客户端不同的端口上的本地IIS 中,并确认它修复了Cors 问题。

然后,我将这两个应用程序都部署到 Azure(我已将这两个应用程序作为 Web 应用程序放在 Azure 上,并且我还尝试将 OWIN 放入当前处于预览状态的 Azure API)但是 - 预检请求现在失败(否Access-Control-Allow-Origin 出现在响应中)。

问:是否有一些我不知道的特定 Azure?为什么 OWIN 在部署时不提供此标头但它在 localhost 上工作?我在应用程序的 Azure 刀片设置的属性窗口中没有看到任何限制。

注意事项:

关于我正在使用的设置的一些细节:

使用OwinWebAPI2NinjectSignalR 自定义令牌在每个后续请求的标头中发布和提供,并使用自定义过滤器进行验证。 我现在尝试的 Cors 是 *

Startup.cs的相关部分:

public void Configuration(IAppBuilder appBuilder)

    appBuilder.UseCors(CorsOptions.AllowAll);

    HttpConfiguration config = new HttpConfiguration();
    config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

    //bind IClientsNotifier with method returning singleton instance of hub
    var ninjectKernel = NinjectWebCommon.GetKernel();
    ninjectKernel.Bind<MySignalRHub>().ToSelf().InSingletonScope();
    ninjectKernel.Bind<QueryStringBearerAuthorizeAttribute>().ToSelf();

    GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(ninjectKernel);
    appBuilder.Map(
        "/signalr", map =>
    
        map.UseCors(CorsOptions.AllowAll);
        var hubConfiguration = new HubConfiguration();
        map.RunSignalR(hubConfiguration);
    );

    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
       name: "DefaultApi",
       routeTemplate: "api/controller/id",
       defaults: new  id = RouteParameter.Optional 
    );

    config.Formatters.Remove(config.Formatters.XmlFormatter);

    config.Filters.Add(new NoCacheHeaderFilter()); //the IE9 fix for cache
    var resolver = new NinjectDependencyResolver(NinjectWebCommon.GetKernel());

config.Filters.Add((System.Web.Http.Filters.IFilter)resolver.GetService(typeof(WebApiAuthenticationFilter)));

    appBuilder.UseNinjectMiddleware(NinjectWebCommon.GetKernel);
    appBuilder.UseNinjectWebApi(config);

此外,为了支持OPTIONS HTTP 请求,我已经注释掉了web.config 中的以下行(否则,它会抛出 HTTP 错误 405)

<system.webServer>
   <handlers>
     <!--<remove name="OPTIONSVerbHandler" />-->
     ...

【问题讨论】:

【参考方案1】:

实际上,Azure 网站应该为您管理 CORS。我想你错过了一个方便的 Azure 网站刀片:

如果我们自己的理解是正确的,那么这个 Azure 中间件的问题是允许您只配置允许的来源。它缺少“允许的标头”可管理配置、每个 URL 规则和其他有用的 CORS HTTP 标头。更糟糕的是:它会从它处理的每个 HTTP 响应中删除所有与 CORS 相关的标头,然后再设置它自己的标头,因此它甚至不允许您处理它没有处理的内容。

好消息是您可以完全禁用此中间件并通过自己的方式管理 CORS,您只需从门户中的 CORS 设置刀片中删除每个允许的来源(包括 *)。然后您可以使用 web.config 或 Web Api 来更具体地处理它。见the documentation:

不要尝试在一个 API 应用中同时使用 Web API CORS 和应用服务 CORS。应用服务 CORS 将优先,Web API CORS 将无效。例如,如果您在应用服务中启用一个源域,并在 Web API 代码中启用所有源域,则您的 Azure API 应用将只接受来自您在 Azure 中指定的域的调用。

另见this related issue:

所以最后的答案是:如果你的应用程序不需要非常具体的 CORS 管理,你可以使用 Azure App Service CORS。否则,您需要自己处理并禁用 Web 应用中的所有 CORS 配置。

【讨论】:

不错的发现...但是列表已经为空,并且 CORS 标头的代码输出仍然被忽略...关于为什么的任何线索? (请注意,当 CORS 在 web.config 中时一切正常) 我只使用 web.config CORS 标头验证了这种行为。如果门户刀片中未配置允许的来源,则保留标头。如果设置了至少一个允许的来源,则 web.config CORS 标头将被忽略。它应该与您的 Web Api CORS 代码相同(appBuilder.UseCors(CorsOptions.AllowAll);),这很奇怪......我们中的一个人可能错过了一些东西。 大家好,我无法让 Azure Cors 工作,听起来你可以 - 请在此处查看我的问题:***.com/questions/41541917/…【参考方案2】:

最后,我采用了更简单的方法 - 删除了 CORS 的所有代码处理,只需将标题放在 web.config 中:

<configuration>
 <system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="http://my-client-website.azurewebsites.net" />
      <add name="Access-Control-Allow-Methods" value="*" />
      <add name="Access-Control-Allow-Headers" value="accept, content-type, x-my-custom-header" />
      <add name="Access-Control-Allow-Credentials" value="true" />
    </customHeaders>
  </httpProtocol>
 ...

(请注意,allow-origin 在 url 的末尾没有斜杠!)

allow-credentials 部分是为了满足 SignalR,可能没有它也可以。

如果有人找到编码方式不起作用的原因,我想知道!

【讨论】:

【参考方案3】:

我也遇到过这个问题。我想我终于让程序化 WebAPI 的 CORS 在 Azure 应用服务中通过处理程序更改的这种神奇组合工作:

  <remove name="OPTIONSVerbHandler" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,POST,PUT,DELETE,HEAD,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

确实必须删除 OPTIONSVerbHandler 以摆脱默认的预检响应——通过在 web.config 中使用自定义标头,您刚刚找到了另一种方法来确保将这些标头写入那些永远不会到达您的应用的 OPTIONS 请求。

关键是确保其他东西负责 OPTIONS 请求,我相信这是通过在动词列表中重新添加指定 OPTIONS 的 ExtensionlessUrlHandler 来实现的。我对 IIS 不太熟悉,所以我在推测这种机制,但它似乎确实有效。 FWIW,这是我在 App_Start/WebApiConfig.cs 中启动 WebAPI 的 CORS 功能,如下所示:

config.EnableCors(new MyCorsPolicyProvider());

其中MyCorsPolicyProvider 是实现ICorsPolicyProvider 的类。

【讨论】:

【参考方案4】:

我在 azure 门户上设置了这个,但是跨域请求的 chrome 预检仍然失败。在 azure 文档中,preflight 使用 OPTION http 动词,我猜 chrome 可能只使用 GET,所以没有标头值。

【讨论】:

在 web.config 中,在 &lt;system.webServer&gt; 下查找 &lt;handlers&gt;。如果您有 &lt;remove name="OPTIONSVerbHandler" /&gt;,则需要将其删除,以便服务可以发送 CORS 的选项,并且它应该开始工作。【参考方案5】:

我的问题是我不小心将 http 而不是 https 放入 Azure AD B2C 自定义页面配置刀片...更改为 https 后它就像一个魅力。

【讨论】:

【参考方案6】:

在 AZURE 云外壳上尝试此命令

Azure cloud shell

az resource update --name web --resource-group ***1*** --namespace Microsoft.Web --resource-type config --parent sites/***2*** --set properties.cors.allowedOrigins="['http://localhost:5000']" --api-version 2015-06-01

****1**** = 您的资源组名称

****2**** = 您的应用名称

【讨论】:

以上是关于在 Azure Web 应用/Azure API 上部署时缺少 CORS 标头的主要内容,如果未能解决你的问题,请参考以下文章

应用之间的 Azure Web 应用访问限制

在访问 Web 应用程序之前忽略对 Azure 应用服务的请求

如何将 azure 广告集成到在 azure 中也使用 REST API 的 React Web 应用程序

Azure - 安全 API 应用程序,因此只有逻辑应用程序和 Web 应用程序可以访问

在 Azure Web 应用程序中为 Web API 启用 CORS

使用 rest api 从 Web 应用程序将文件上传到 Azure 文件存储