Подтвердить что ты не робот

Аутентификация AD FS 2.0 и AJAX

У меня есть веб-сайт, который пытается вызвать действие контроллера MVC на другом веб-сайте. Эти сайты устанавливаются как доверительные доверительные отношения в AD FS 2.0. Все аутентифицируется и отлично работает при открытии страниц в окне браузера между двумя сайтами. Однако при попытке вызвать действие контроллера из JavaScript с использованием метода jQuery AJAX он всегда терпит неудачу. Вот фрагмент кода того, что я пытаюсь сделать...

$.ajax({
  url: "relyingPartySite/Controller/Action",
  data: { foobar },
  dataType: "json",
  type: "POST",
  async: false,
  cache: false,
  success: function (data) {
    // do something here
  },
  error: function (data, status) {
    alert(status);
  }
});

Проблема заключается в том, что AD FS использует JavaScript для отправки скрытой формы html доверяющей стороне. При трассировке с Fiddler я вижу, что он попадает на сайт AD FS и возвращает эту html-форму, которая должна публиковать и перенаправлять на действие контроллера, прошедшее проверку подлинности. Проблема заключается в том, что эта форма возвращается в результате запроса ajax и, очевидно, будет терпеть неудачу с ошибкой парсера, поскольку запрос ajax ожидает json от действия контроллера. Похоже, что это будет распространенным сценарием, так что, как правильно связаться с AD FS из AJAX и обрабатывать это перенаправление?

4b9b3361

Ответ 1

У вас есть два варианта. Подробнее здесь.

Первым делом является совместное использование cookie сеанса между приложением ввода (на основе HTML) и вашими решениями API. Вы настроите оба приложения на использование одного и того же файла cookie WIF. Это работает только в том случае, если оба приложения находятся в одном корневом домене. См. Вышеприведенную статью или этот вопрос о стеке_перехода.

Другой вариант - отключить запросы passiveRedirect для AJAX (как ответ Gutek). Это вернет код статуса http 401, который вы можете обрабатывать в Javascript. Когда вы обнаруживаете 401, вы загружаете фиктивную страницу (или диалоговое окно "Аутентификация", которое может быть двойным в качестве диалогового окна входа в систему, если учетные данные должны быть указаны снова) в iFrame. Когда iFrame завершится, вы снова попытаетесь выполнить вызов. На этот раз cookie сеанса будет присутствовать в вызове, и он должен преуспеть.

//Requires Jquery 1.9+
var webAPIHtmlPage = "http://webapi.somedomain/preauth.html"

function authenticate() {
    return $.Deferred(function (d) {
        //Potentially could make this into a little popup layer 
        //that shows we are authenticating, and allows for re-authentication if needed
        var iFrame = $("<iframe></iframe>");
        iFrame.hide();
        iFrame.appendTo("body");
        iFrame.attr('src', webAPIHtmlPage);
        iFrame.load(function () {
            iFrame.remove();
            d.resolve();
        });
    });
};

function makeCall() {
    return $.getJSON(uri)
                .then(function(data) {
                        return $.Deferred(function(d) { d.resolve(data); });
                    },
                    function(error) {
                        if (error.status == 401) {
                            //Authenticating, 
                            //TODO:should add a check to prevnet infinite loop
                            return authenticate().then(function() {
                                //Making the call again
                                return makeCall();

                            });
                        } else {
                            return $.Deferred(function(d) {
                                d.reject(error);
                            });
                        }
                });
}

Ответ 2

Если вы не хотите получать HTML со ссылкой, вы можете обрабатывать AuthorizationFailed на WSFederationAuthenticationModule и устанавливать RedirectToIdentityProvider в false только для вызовов Ajax.

например:

FederatedAuthentication.WSFederationAuthenticationModule.AuthorizationFailed += (sender, e) =>
{
    if (Context.Request.RequestContext.HttpContext.Request.IsAjaxRequest())
    {
        e.RedirectToIdentityProvider = false;
    }
};

Этот атрибут Authorize вернет вам код состояния 401, и если вы хотите иметь что-то другое, тогда вы можете реализовать собственный атрибут Authorize и написать специальный код в Ajax Request.

Ответ 3

Прежде всего, вы говорите, что пытаетесь сделать аякс-вызов на другом веб-сайте, соответствует ли ваш вызов той же политике происхождения веб-браузеров? Если это произойдет, вы ожидаете html в качестве ответа от вашего сервера, измените datatype на вызов ajax на dataType: "html", затем вставьте форму в свой DOM.

Ответ 4

Возможно, вам помогут 2 первых сообщения эта серия. Они рассматривают запросы ADFS и AJAX

Я думаю, что я попытаюсь понять, почему куки аутентификации не передаются через ajax и найти среднее для отправки их с моим запросом. Или заверните вызов ajax в функцию, которая предварительно аутентифицируется, извлекая форму html, добавив ее в DOM, отправив ее (она, надеюсь, установит хорошие куки), затем отправит соответствующий запрос, который вы хотите отправить изначально

Ответ 5

Вы можете использовать только тип данных типа

"xml": Treat the response as an XML document that can be processed via jQuery. 

"html": Treat the response as HTML (plain text); included script tags are evaluated. 

"script": Evaluates the response as JavaScript and evaluates it. 

"json": Evaluates the response as JSON and sends a JavaScript Object to the success callback. 

Если вы видите в своем скрипаче, который возвращает только html, то измените свой тип данных на html или если это только код script, то вы можете использовать script.

Ответ 6

В проекте, с которым я сейчас работаю, у нас была та же проблема с истечением токена SAML на стороне клиента и причиной проблем с вызовами ajax. В нашем конкретном случае нам потребовались все запросы, которые должны быть enqueud после первого 401, и после успешной аутентификации все они могут быть повторно отправлены. Аутентификация использует решение iframe, предложенное Адамом Миллсом, но также идет немного дальше, в случае необходимости вводить учетные данные пользователя, что делается путем отображения диалогового окна, информирующего пользователя о входе во внешний вид (поскольку ADFS не позволяет отображать логин страницы в iframe по крайней мере не по умолчанию), в течение которого ожидающий запрос ожидает завершения, но пользователю необходимо войти в систему с внешней страницы. Запросы ожидания также могут быть отклонены, если пользователь выбирает Cancel, и в этих случаях для каждого запроса будет вызываться ошибка jquery.

Здесь ссылка на суть с примером кода:

https://gist.github.com/kaveh82/bb0d8e4a446496a6c05a

Обратите внимание, что мой код основан на использовании jquery для обработки всего запроса ajax. Если ваш запрос ajax обрабатывается ванильным javascript, другими библиотеками или фреймворками, то вы можете найти вдохновение в этом примере. Использование jquery ui происходит только из-за диалога и означает небольшую часть кода, который можно легко поменять.

Ответ 7

Вы должны создать файл anyname, например json.php, а затем поместить соединение на сайт relayparty, это должно работать       $.ajax({ url: "json.php", data: { foobar }, dataType: "json", type: "POST", async: false, cache: false, success: function (data) { // do something here }, error: function (data, status) { alert(status); } });