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

Предотвращение HTTP Basic Auth Dialog с использованием AngularJS Interceptors

Я создаю веб-приложение AngularJS (1.2.16) с API RESTful, и я бы хотел отправить 401 Несанкционированные ответы на запросы, в которых данные аутентификации являются недействительными или нет. Когда я это делаю, даже с присутствующим HTTP-перехватчиком, я вижу представленный браузером базовый диалог "Требуется проверка подлинности", когда запрос AJAX выполняется через AngularJS. Мой перехватчик запускается после этого диалога, что слишком поздно, чтобы сделать что-то полезное.

Конкретный пример:

My backend API возвращает 401 для /api/things, если нет токена авторизации. Приятно и просто.

На стороне приложения AngularJS я просмотрел docs и настроил такой перехватчик в блоке config

$httpProvider.interceptors.push(['$q', function ($q) {
  return {
    'responseError': function (rejection) {
      if (rejection.status === 401) {
        console.log('Got a 401')
      }
      return $q.reject(rejection)
    }
  }
}])

Когда я загружаю свое приложение, удаляю токен аутентификации и выполняю вызов AJAX /api/things (чтобы, надеюсь, запустить вышеупомянутый перехватчик), я вижу следующее:

Authentication Required

Если я отменил это диалоговое окно, я вижу вывод console.log "Got a 401", который я надеялся увидеть вместо этого диалога:

Got a 401

Ясно, что перехватчик работает, но перехватывает слишком поздно!

Я вижу многочисленные сообщения в Интернете об аутентификации с помощью AngularJS в ситуациях, подобных этому, и все они, похоже, используют HTTP-перехватчики, но ни один из них не упоминает об открытии основного диалога auth. Некоторые ошибочные мысли, которые я имел для его появления, включали:

  • Отсутствует заголовок Content-Type: application/json в ответе? Нет, это там.
  • Нужно вернуть что-то другое, кроме обещания отклонения? Этот код всегда запускается после диалога, независимо от того, что возвращается.

Я пропустил какой-то шаг установки или неправильно использовал перехватчик?

4b9b3361

Ответ 1

Выяснилось!

Трюк состоял в том, чтобы отправить заголовок ответа WWW-Authenticate некоторого значения, отличного от Basic. Затем вы можете захватить 401 с помощью базового перехватчика $http или что-то еще более умное, например angular-http-auth.

Ответ 2

У меня была эта проблема вместе с Spring Boot Security (HTTP basic), а с Angular 1.3 вам нужно установить $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';, чтобы всплывающее окно не отображалось.

Ответ 3

Для справок в будущем

Я придумал это решение, пытаясь обработать ошибки 401. У меня не было возможности переписать Basic на x-Basic или что-то подобное, поэтому я решил обработать его на стороне клиента с помощью Angular.

При инициировании выхода из системы сначала попробуйте сделать неверный запрос с поддельным пользователем, чтобы выбросить кэшированные учетные данные.

У меня есть эта функция, выполняющая запросы (она использует jquery $.ajax с отключенными асинхронными вызовами):

function authenticateUser(username, hash) {
    var result = false;
    var encoded = btoa(username + ':' + hash);

    $.ajax({
        type: "POST",
        beforeSend: function (request) {
            request.setRequestHeader("Authorization", 'Basic ' + encoded);
        },
        url: "user/current",
        statusCode: {
            401: function () {
                result = false;
            },
            200: function (response) {
                result = response;
            }
        },
        async: false
    });

    return result;
}

Итак, когда я пытаюсь вывести пользователя из системы, это происходит:

//This will send a request with a non-existant user.
//The purpose is to overwrite the cached data with something else
accountServices.authenticateUser('logout','logout');

//Since setting headers.common.Authorization = '' will still send some
//kind of auth data, I've redefined the headers.common object to get
//rid of the Authorization property
$http.defaults.headers.common = {Accept: "application/json, text/plain, */*"};