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

时间:2016-04-20 10:53:23

标签: c# azure cors azure-web-sites azure-api-apps

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

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

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

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

注意:

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

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

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);
}

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

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

6 个答案:

答案 0 :(得分:15)

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

Azure Websites CORS blade

如果我们自己的理解是正确的,那么这个Azure中间件的问题在于,它允许您配置除允许的起源之外的任何内容。它缺少一个允许的标题&#34;可管理的配置,每URL规则和其他有用的CORS HTTP标头。更糟糕的是:它会在设置自己的每个HTTP响应之前丢弃所有与CORS相关的标头,因此它甚至不能让你处理它所做的事情。

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

  

请勿尝试在一个API应用中同时使用Web API CORS和App Service CORS。 App Service CORS优先,Web API CORS不起作用。例如,如果在App Service中启用一个源域,并在Web API代码中启用所有源域,则Azure API应用程序将仅接受来自您在Azure中指定的域的调用。

另见this related issue

  

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

答案 1 :(得分:4)

最后,我采用了更简单的方式 - 删除了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,可能没有它。

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

答案 2 :(得分:1)

我也遇到过这个问题。我想我终于让程序化的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的ExtensionlessUrlHandler来实现。我不熟悉IIS,所以我猜测机制,但它似乎确实有效。 FWIW,这是我在App_Start / WebApiConfig.cs中启动WebAPI的CORS功能,如下所示:

config.EnableCors(new MyCorsPolicyProvider());

MyCorsPolicyProvider是一个实现ICorsPolicyProvider的类。

答案 3 :(得分:0)

我在azure portal上设置了这个,但是对于跨域请求,chrome预检仍然失败。在azure文档中,预检使用OPTION http动词,我猜chrome可能只使用GET,因此没有标题值。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

在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 **** =您的应用名称