Запрос CORS preflight отвечает перенаправлением 302 в размещенном веб-API Azure

сценарий:

у меня два ASP.NET веб-приложения, размещенные отдельно в Windows Azure и связанные с одним и тем же клиентом Azure Active Directory:

  1. приложение MVC с интерфейсом AngularJS SPA и Адал.js библиотека для обработки проверки подлинности Azure AD на клиента.

  2. веб-API с промежуточным ПО Microsoft OWIN для обработки проверки подлинности Azure AD на сервер.

:

когда angular загружает клиентское приложение, страница загружается правильно после прохождения OAuth перенаправляет на соответствующий орган идентификации и adal.библиотека js правильно извлекает и хранит различные маркеры для каждого приложения (проверено путем проверки вкладки ресурсы / хранилище сеансов в Chrome dev tools). но когда клиентское приложение пытается получить доступ или обновить любые данные в API, CORS предполетные запросы отвечают с 302 перенаправлениями в центр идентификации, что приводит к следующей ошибке в консоли:

XMLHttpRequest не удается загрузить https://webapi.azurewebsites.net/api/items. Запрос был перенаправлен на 'https://login.windows.net/{authority-guid}/oauth2/authorize?response_type=id_token&redirect_uri=....etc..etc..', который запрещен для запросов перекрестного происхождения, которые требуют предполетный.

примеры заголовков (анонимные):

Request
OPTIONS /api/items HTTP/1.1
Host: webapi.azurewebsites.net
Connection: keep-alive
Access-Control-Request-Method: GET
Access-Control-Request-Headers: accept, authorization
Origin: https://mvcapp.azurewebsites.net
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36
Accept: */*
Referer: https://mvcapp.azurewebsites.net/

Response
HTTP/1.1 302 Found
Content-Length: 504
Location: https://login.windows.net/{authority-guid}/oauth2/authorize?response_type=id_token&redirect_uri=https%3A%2F%2F....etc..etc.%2F&client_id={api-guid}&scope=openid+profile+email&response_mode=form_post&state=...etc...
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=4f51...snip....redact....db6d;Path=/;Domain=webapi.azurewebsites.net

что я сделал / попробовал

  1. обеспечено, что клиент Azure AD разрешает неявный поток OAuth2, как описано здесь и в другом месте.
  2. гарантировал, что API предоставляет права доступа и что MVC / SPA регистры для доступа использование этих открытых разрешений.
  3. явно добавили Параметры обработчика глаголов в веб-интерфейсе API.конфиг (см. ниже).
  4. используются различные комбинации включения CORS на сервере API, OWIN сам по себе, а также с EnableCorsAttribute (см. ниже).

вопросы

есть ли способ, чтобы веб-API, связанный с клиентом Azure AD, не перенаправлялся на запросы предварительной подготовки CORS? Я пропустил некоторую настройку инициализации в adal.библиотека js и / или код запуска OWIN (см. ниже)? Быть там параметры на портале Azure, которые позволят выполнять запросы параметров в конвейер OWIN?

соответствующий код:

Адал.инициализации в JS

angular.module("myApp", ["ngRoute", "AdalAngular"])

.config(["$routeProvider", "$locationProvider", "$httpProvider", "adalAuthenticationServiceProvider",
    function ($routeProvider, $locationProvider, $httpProvider, adalProvider) {

        $routeProvider.when("/", { // other routes omitted for brevity
            templateUrl: "/content/views/home.html",
            requireADLogin: true // restrict to validated users in the Azure AD tenant
        });

        // CORS support (I've tried with and without this line)
        $httpProvider.defaults.withCredentials = true;

        adalProvider.init({
            tenant: "contoso.onmicrosoft.com",
            clientId: "11111111-aaaa-2222-bbbb-3333cccc4444", // Azure id of the web app
            endpoints: {
                // URL and Azure id of the web api
                "https://webapi.azurewebsites.net/": "99999999-zzzz-8888-yyyy-7777xxxx6666"
            }
        }, $httpProvider);
    }
]);

инициализация промежуточного программного обеспечения OWIN

public void ConfigureAuth(IAppBuilder app)
{
    // I've tried with and without the below line and also by passing
    // in a more restrictive and explicit custom CorsOptions object
    app.UseCors(CorsOptions.AllowAll);

    app.UseWindowsAzureActiveDirectoryBearerAuthentication(
        new WindowsAzureActiveDirectoryBearerAuthenticationOptions
        {
            TokenValidationParameters = new TokenValidationParameters
            {
                // Azure id of the Web API, also tried the client app id
                ValidAudience = "99999999-zzzz-8888-yyyy-7777xxxx6666"
            },
            Tenant = "contoso.onmicrosoft.com"
        }
    );

    // I've tried with and without this
    app.UseWebApi(GlobalConfiguration.Configuration);
}

инициализация WebApiConfig

public static void Register(HttpConfiguration config)
{
    // I've tried with and without this and also using both this
    // and the OWIN CORS setup above. Decorating the ApiControllers
    // or specific Action methods with a similar EnableCors attribute
    // also doesn't work.
    var cors = new EnableCorsAttribute("https://mvcapp.azurewebsites.net", "*", "*")
    {
        cors.SupportsCredentials = true // tried with and without
    };
    config.EnableCors(cors);

    // Route registration and other initialization code removed
}

параметры API Регистрация обработчика глаголов

<system.webServer>
  <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    <remove name="OPTIONSVerbHandler" />
    <remove name="TRACEVerbHandler" />
    <add name="OPTIONSHandler" path="*" verb="OPTIONS" modules="IsapiModule" scriptProcessor="C:WindowsMicrosoft.NETFramework64v4.0.30319aspnet_isapi.dll" />
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  </handlers>
</system.webServer>

связанные ресурсы

в то или иное время я старался всеми мыслимыми комбинация вещей из следующих (и многих других) сообщений форума и блога и примера кода github.

  1. Adal JavaScript и AngularJS-глубокое погружение
  2. Безопасный ASP.NET веб-API 2 с использованием Azure Active Directory, промежуточного программного обеспечения Owin и ADAL
  3. аутентификация на основе токенов с использованием ASP.NET Web API 2, Owin и Identity
  4. AzureADSamples / SinglePageApp-DotNet (github)
  5. AngularJSCORS (github)
  6. как сделать аутентификацию CORS в WebAPI 2?
  7. проверка подлинности AngularJS и OWIN на WebApi

2 ответов


у меня были аналогичные проблемы, чтобы выяснить правильные пакеты для этого. Только Owin cors достаточно для настройки.Пожалуйста, проверьте пакеты в долг.пдбс первый.

<package id="Microsoft.Owin" version="3.0.0" targetFramework="net45" />
<package id="Microsoft.Owin.Cors" version="2.1.0" targetFramework="net45" />

параметры WebConfig для обработчиков:

<system.webServer>
<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

Вы делаете правильно с опцией specfiying cors в конфигурации owin.

 public void ConfigureAuth(IAppBuilder app)
    {
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Audience = ConfigurationManager.AppSettings["ida:Audience"],
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"]

            });
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    }

контроллеру не нужны атрибуты, связанные с CORS.

   [Authorize]
public class ContactsController : ApiController
{

    // GET api/<controller>
    public IEnumerable<string> Get()
    {
        return new string[] { "person1", "person2" };
    }

    // GET api/<controller>/5
    public string Get(int id)
    {
        return "person" + id;
    }

WebAPIConfig не нуждается в записи, связанной с CORS.

рабочая пример здесь:https://github.com/omercs/corsapisample

вы можете проверить в своем приложении со следующим кодом:

app.factory('contactService', ['$http', function ($http) {
var serviceFactory = {};

var _getItems = function () {
    $http.defaults.useXDomain = true;
    delete $http.defaults.headers.common['X-Requested-With'];
    return $http.get('http://yourhostedpage/api/contacts');
};

serviceFactory.getItems = _getItems;

return serviceFactory;

}]);

пример предполетный ответ:

Remote Address:127.0.0.1:8888
Request URL:http://localhost:39725/api/contacts
Request Method:OPTIONS
Status Code:200 OK
Request Headersview source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, authorization
Access-Control-Request-Method:GET
Host:localhost:39725
Origin:http://localhost:49726
Proxy-Connection:keep-alive
Referer:http://localhost:49726/myspa.html
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36
Response Headersview source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:authorization
Access-Control-Allow-Origin:http://localhost:49726
Content-Length:0
Date:Fri, 23 Jan 2015 01:10:54 GMT
Server:Microsoft-IIS/8.0
X-Powered-By:ASP.NET

решена (вроде)

Это, по-видимому, было вызвано проблемами развертывания, в частности тем, как я первоначально опубликовал приложения в Azure. Оба приложения были первоначально написаны с использованием проверки подлинности Windows и были развернуты на стандартном (т. е. не Azure) веб-сервере. Используя эти технологии, приложения работали так, как ожидалось.

для новых бизнес-требований я работаю над их миграцией в Azure. Процесс я следовал было:

  1. развертывание / публикация обоих приложений, как было первоначально написано, из Мастера публикации Visual Studio 2013 непосредственно в Azure. Конечно, это сломалось, как и ожидалось, поскольку они не могли связаться с локальным Active Directory из Azure.
  2. постепенно обновите код, чтобы удалить Windows Auth и заменить его Azure AD auth, следуя инструкциям из всех ссылок в конце вопроса.
  3. вручную связать приложения с клиентом Azure AD для проверки подлинности с помощью портала Azure AD.

в какой-то момент я заметил параметр включить организационную аутентификацию на вкладке Настройки мастера публикации VS и начал использовать его для связывания приложений с арендатором. Поскольку я уже связал их вручную, Visual Studio в конечном итоге создала еще одно приложение Azure AD для каждого из них.

В конце концов, это то, что сделал:

  1. удалены все Azure записи для обоих приложений, использующих портал, как самих веб-сайтов Azure, так и сайтов/ассоциаций Azure AD.
  2. вернул все изменения кода в обоих приложениях в исходное состояние.
  3. Переопределенная аутентификация Azure AD (OWIN, adal.js и т. д.) В приложениях.
  4. сделала новую публикацию обоих приложений, позволяя мастеру VS обрабатывать все ассоциации Azure.
  5. обновили веб.конфигурационные файлы и adal.инициализация js с вновь созданным идентификатор клиента.
  6. снова опубликовал.

теперь параметры предполетных запросов больше не 302 перенаправления.

вместо этого они теперь 405 метод не допускается, очень похож на этой теме. Своего рода прогресс.

несмотря на то, что он все еще не работает от начала до конца, я оставлю этот ответ (а не удалю вопрос), если это может помочь другим, испытывающим переадресацию Azure 302 CORS.