2015-01-22 2 views
3

Сценарий:CORS предполетной запрос отвечает 302 редирект в Azure Hosted Web API

Я два веб-приложения ASP.NET размещается отдельно на Windows Azure и оба связаны с тем же Azure Справочник жильца Активный:

  1. Приложение MVC с интерфейсом AngularJS SPA и библиотекой adal.js для обработки аутентификации Azure AD на клиенте.

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

Проблема:

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

XMLHttpRequest не может загрузить https://webapi.azurewebsites.net/api/items , Запрос был перенаправлен на 'https://login.windows.net/ {власти-справ}/OAuth2/авторизовать? 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. обеспечивших AD арендатор Azure позволяет OAuth2 неявного поток, как описан here и в других местах ,
  2. Убедитесь, что API exposes access permissions и что MVC/SPA registers for access использует эти разрешенные разрешения.
  3. Явно добавлен обработчик глагола OPTIONS в web.config API (см. Ниже).
  4. Используется различные комбинации включения CORS на сервере API, OWIN, а также с EnableCorsAttribute (см. Ниже).

Вопросы

Есть ли способ иметь Web API, связанный с Azure AD арендатором не перенаправляет на CORS предполетных запросах? Я пропустил некоторые настройки инициализации в библиотеке adal.js и/или в стартовом коде OWIN (см. Ниже)? Существуют ли настройки на портале Azure, которые разрешат запросы OPTIONS к конвейеру OWIN?

Соответствующий код: Инициализация

adal.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 OPTIONS регистрация обработчика глагола

<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:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_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 and AngularJS – Deep Dive
  2. Secure ASP.NET Web API 2 using Azure Active Directory, Owin Middleware, and ADAL
  3. Token Based Authentication using ASP.NET Web API 2, Owin, and Identity
  4. AzureADSamples/SinglePageApp-DotNet (github)
  5. AngularJSCORS (github)
  6. How to make CORS Authentication in WebAPI 2?
  7. AngularJS and OWIN Authentication on WebApi

ответ

3

решаемые (вроде)

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

По новым бизнес-требованиям, я работал над их переносом на Azure. Следующим процессом я был:

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

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

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

  1. Удалены все Azure записи для обоих приложений с использованием портала, как сами Azure сайты, а также сайты Azure AD/объединения.
  2. Вернул все изменения кода в обоих приложениях в исходное состояние.
  3. В приложениях реализована функция ADRE ADRE AD (OWIN, adal.js и т. Д.).
  4. Была ли новая публикация обоих приложений позволяющей VS Wizard обрабатывать все ассоциации Azure.
  5. Обновлены файлы Web.config и инициализация adal.js с помощью вновь созданных идентификаторов клиентов.
  6. Опубликовано снова.

Теперь запросы предварительной проверки OPTIONS больше не переадресованы 302.

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

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

+0

Вы когда-нибудь решали эту проблему? Я застрял на 302 и попробовал все, чтобы обойти это. Я удалил все и начал много раз. Любая помощь, которую вы можете предоставить, будет очень признательна. –

+0

@ IsaacLevin, 302 был разрешен, как описано выше. Последующие 405 также были решены не слишком долго, но я, честно говоря, не помню, что это за решение. – Bryan

+0

Есть ли шанс, что вы можете предоставить свое решение в Git, а также экраны вашего экрана Azure? Я понимаю, если это слишком много, чтобы просить, но я нахожусь здесь на своем пути :) –

3

У меня были аналогичные проблемы, чтобы выяснить правильные пакеты для этого. Только Owin cors достаточно для установки. Пожалуйста, сначала проверьте пакеты для 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 варианта Корса в 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 
+0

Спасибо за ответ. У вас установлена ​​более ранняя версия пакета Microsoft.Owin.Cors NuGet (я использую 3.0.0) и вместо идентификатора арендатора вместо идентификатора арендатора используют идентификатор арендатора для инициализации Owin и adal.js. Кроме того, это в основном идентично. Надеясь на надежду, я поменялся на более ранний пакет и попытался использовать идентификатор арендатора. К сожалению, нет кубиков. Можете ли вы разместить заголовки запроса и ответа для запроса предварительной проверки OPTIONS, выполненного из вашего рабочего примера? Мне было бы любопытно посмотреть, как они отличаются друг от друга. – Bryan

+0

Я добавил пример запроса опции. Получаете ли вы ошибки с 302? Это может быть связано с настройкой разрешений для приложений. Я также обновил рабочий образец. –

+0

Спасибо за публикацию заголовков. Интересно. И, да, я настроил разрешения в обоих приложениях для доступа к Azure AD. Я обновил вопрос, добавив эту часть в раздел «Что я пробовал». – Bryan