Отсутствующие заголовки CORS при развертывании на веб-приложения Azure и Azure API-интерфейс


Я создал OWIN hosted WebAPI 2. Существует также веб-приложение (AngularJS), которое использует API и действует как клиент.

Я добавил необходимый код для CORS к Startup.cs, и разместил его в локальных IIS на порту, отличном от клиента, и подтвердил, что он исправляет проблему Cors.

Затем я развернул оба приложения в Azure (я поместил оба в Azure как веб-приложение, а также попытался поместить OWIN в API Azure, который в настоящее время находится в предварительном просмотре), но ... запрос теперь не выполняется (нет Access-Control-Allow-Origin в ответе).

Вопрос: есть ли какая-то специфика Azure, о которой я не знаю? Как получилось, что OWIN не обслуживает этот заголовок при развертывании, но работает на localhost? Я не вижу никаких ограничений в окне свойств параметров блейдов Azure для приложений.

Примечания:

О некоторых особенностях настройки, которую я использую:

  • использование Owin, WebAPI2, Ninject, SignalR
  • пользовательский токен выдается и предоставляется в заголовки на каждом последующем запросе, и проверяется с помощью пользовательского фильтра.
  • Корс, который я пытаюсь сейчас, это *

Соответствующая часть стартапа.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, Чтобы поддержать запрос HTTP OPTIONS (в противном случае он вызывал ошибку HTTP 405)

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

5 ответов:

На самом деле веб-сайт Azure должен управлять CORS для вас. Я думаю, вы пропустили удобный веб-сайт Azure blade:

Веб-сайты Azure CORS blade

Если наше собственное понимание верно, проблема с этим промежуточным программным обеспечением Azure заключается в том, что оно не позволяет настраивать ничего, кроме разрешенных источников. В нем отсутствует управляемая конфигурация "разрешенных заголовков", правила для каждого URL-адреса и другие полезные заголовки HTTP CORS. Хуже того: он отбрасывает все заголовки, связанные с CORS, из каждого отдельного ответа HTTP, который он обрабатывает, прежде чем устанавливая свои собственные, так что он даже не позволяет вам справиться с тем, что он не делает.

Хорошо то, что вы можете полностью отключить это промежуточное программное обеспечение и управлять CORS своими собственными средствами, вам просто нужно удалить все разрешенные источники (включая *) из Блейда настроек CORS на портале. Тогда вы можете использовать веб.config или Web Api для более конкретной обработки. Смотрите документацию:

Не пытайтесь использовать как Web API CORS, так и App Service CORS в одном приложении API. Апп Сервисные CORS будут иметь приоритет, а Web API CORS не будет иметь никакого эффекта. Например, если включить один исходный домен в Службе приложений и включить все исходные домены в коде веб-API, приложение API Azure будет принимать вызовы только из домена, указанного в Azure.

См. также этот связанный вопрос :

Таким образом, окончательный ответ таков: Если ваше приложение не нуждается в очень специфическом управлении CORS, вы можете использовать службу приложений Azure CORS. В противном случае вам придется справьтесь с этим самостоятельно и отключите все настройки CORS в веб-приложении.

В конце концов я пошел более простым путем-удалил всю обработку кода 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-адреса!)

Разрешающая часть должна была удовлетворить SignalR, вероятно, он мог бы обойтись без нее.

Если кто-то найдет причину, почему кодированный способ не работает, я хотел бы знать!

Я тоже сталкивался с этой проблемой. Я думаю, что наконец-то получил программный 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, чтобы избавиться от ответов перед полетом по умолчанию-с помощью пользовательских заголовков в интернете.config, вы просто нашли другой способ гарантировать, что эти заголовки будут записаны в те запросы опций, которые никогда не достигнут вашего приложения.

Ключ в том, чтобы убедиться, что что-то else отвечает за запросы опций, и я считаю, что это достигается путем повторного добавления ExtensionlessUrlHandler, указывающего опции в списке глаголов. Я не очень хорошо разбираюсь в IIS, поэтому я размышляю о механизме, но он, кажется, работает. Чистки рядов, это со мной крутится функциональность ПДБС веб-API в файл App_Start/WebApiConfig.cs вот так:

config.EnableCors(new MyCorsPolicyProvider());

Где MyCorsPolicyProvider - класс, реализующий ICorsPolicyProvider.

Я установил это на портале azure, но Chrome preflight по-прежнему не удается выполнить междоменный запрос. В документе azure preflight использует опцию http verb, я предполагаю, что chrome может просто использовать GET, поэтому для этого нет значения заголовка.

Моя проблема заключалась в том, что я случайно поместил http вместо https в колонку конфигурации настраиваемой страницы Azure AD B2C ... После перехода на https он работает как заклинание.