Как я могу подавить диалог аутентификации браузера?

85

В моем веб-приложении есть страница входа, которая отправляет учетные данные для аутентификации через вызов AJAX. Если пользователь вводит правильное имя пользователя и пароль, все в порядке, но если нет, происходит следующее:

  1. Веб-сервер определяет, что, хотя запрос включал правильно сформированный заголовок авторизации, учетные данные в заголовке не проходят успешную аутентификацию.
  2. Веб-сервер возвращает код состояния 401 и включает один или несколько заголовков WWW-Authenticate, в которых перечислены поддерживаемые типы аутентификации.
  3. Браузер обнаруживает, что ответ на мой вызов объекта XMLHttpRequest - это 401, а ответ включает заголовки WWW-Authenticate. Затем появляется диалоговое окно аутентификации, снова запрашивающее имя пользователя и пароль.

Все в порядке до шага 3. Я не хочу, чтобы диалоговое окно всплывало, я хочу обработать ответ 401 в моей функции обратного вызова AJAX. (Например, отображая сообщение об ошибке на странице входа в систему.) Я хочу, чтобы пользователь повторно ввел свое имя пользователя и пароль, конечно, но я хочу, чтобы они видели мою дружелюбную, обнадеживающую форму входа в систему, а не уродливую форму браузера по умолчанию. диалог аутентификации.

Между прочим, у меня нет контроля над сервером, поэтому он не может возвращать пользовательский код состояния (то есть что-то кроме 401).

Есть ли способ подавить диалог аутентификации? В частности, могу ли я подавить диалоговое окно «Требуется аутентификация» в Firefox 2 или новее? Есть ли способ отключить диалоговое окно «Подключение к [хосту] » в IE 6 и более поздних версиях?


Изменить
Дополнительная информация от автора (18 сентября):
я должен добавить, что настоящая проблема с появлением диалогового окна аутентификации браузера заключается в том, что он не предоставляет пользователю недостаточной информации.

Пользователь только что ввел имя пользователя и пароль через форму на странице входа, он считает, что ввел их правильно, и он нажал кнопку отправки или клавишу ввода. Он ожидает, что его переместят на следующую страницу или, возможно, ему скажут, что он ввел свои данные неправильно и должен повторить попытку. Однако вместо этого ему предоставляется неожиданное диалоговое окно.

Диалог не подтверждает того факта, что он только что ввел имя пользователя и пароль. В нем нет четкого указания на то, что возникла проблема и что он должен попробовать еще раз. Вместо этого диалоговое окно представляет пользователю загадочную информацию вроде «На сайте написано: ' [область] '». Где [область] - это короткое имя области, которое может полюбить только программист.

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

dgvid
источник
1
Ответ в том, что нет хорошего ответа. Хаки, предложенные Марин, настолько близки, насколько это возможно. Конечно, использование пользовательской аутентификации, понятной серверу и вашему JavaScript, но не браузеру, также поможет, если это возможно.
dgvid
Я столкнулся с той же проблемой и нашел эту ссылку в комментарии здесь, на stackoverflow (не в моем блоге): Loudvchar.blogspot.ca/2010/11/… Надеюсь, это поможет вам.
gies0r

Ответы:

17

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

  1. Возможно, Flash справится с этим по-другому (я еще не пробовал), поэтому запрос на создание флэш-ролика может помочь.

  2. Вы можете настроить «прокси» для службы, к которой вы обращаетесь, на своем собственном сервере и заставить его немного изменить заголовки аутентификации, чтобы браузер их не распознал.

Marijn
источник
«Невозможно» кажется правильным ответом, хотя я подозреваю, что взлом «прокси» поможет.
dgvid
@Stobor Принятый ответ на дубликат, который вы разместили, на самом деле ссылается на этот вопрос в качестве ответа!
8bitjunkie
3
@ 7SpecialGems Хороший улов. Я не предполагал, что это обман, я связался с конкретным ответом (WWW-Authenticate), который был опубликован через 4 года после принятого ответа. Хотя, оглядываясь назад, я не могу вспомнить, почему я смотрел на это или как я это проверял.
Stobor
1
Я пытаюсь отловить несанкционированную ошибку 401 с помощью этого кода: $ .ajaxSetup ({statusCode: {401: function () {RedirectToLogin ();}}}); Но IE всегда показывает диалог аутентификации браузера. Как я могу подавить этот диалог в ASP.Net MVC 2?
PaulP
@PaulP, как уже было сказано, вам нужен прокси, который удалит ответ с кодом состояния 401 из их заголовка WWW-Authenticate или какая-то особая реализация сервера.
Motes
51

Я столкнулся с той же проблемой здесь, и бэкэнд-инженер в моей компании реализовал поведение, которое, по-видимому, считается хорошей практикой: когда вызов URL-адреса возвращает 401, если клиент установил заголовок X-Requested-With: XMLHttpRequest, сервер отбрасывает www-authenticateзаголовок в своем ответ.

Побочным эффектом является то, что всплывающее окно аутентификации по умолчанию не появляется.

Убедитесь, что для вашего вызова API установлен X-Requested-Withзаголовок XMLHttpRequest. В таком случае ничего не остается, кроме как изменить поведение сервера в соответствии с этой хорошей практикой ...

Антуан Банктель-Шеврель
источник
3
Если бэкэнд основан на Java / Spring, он DelegatingAuthenticationEntryPointобрабатывает это поведение за вас.
Дерек Слайф 04
Спасибо тебе за это. Многие библиотеки переняли это поведение, в том числе Devise
josephnvu
1
есть идеи, как это сделать в nginx? «когда вызов URL-адреса возвращает 401, если клиент установил заголовок X-Requested-With: XMLHttpRequest, сервер отбрасывает заголовок www-Authenticate в своем ответе».
markmnl 03
18

В браузере появляется всплывающее окно с запросом на вход в систему, когда выполняются оба следующих условия:

  1. Статус HTTP - 4xx
  2. WWW-Authenticate заголовок присутствует в ответе

Если вы можете управлять ответом HTTP, вы можете удалить WWW-Authenticateзаголовок из ответа, и браузер не будет отображать диалоговое окно входа в систему.

Если вы не можете контролировать ответ, вы можете настроить прокси для фильтрации WWW-Authenticateзаголовка из ответа.

Насколько я знаю (не стесняйтесь поправлять меня, если я ошибаюсь), нет никакого способа предотвратить приглашение входа в систему после того, как браузер получит WWW-Authenticateзаголовок.

ржавый
источник
Хорошая информация. Что касается допустимых WWW-Authenticateзначений заголовков см stackoverflow.com/a/1748451/225217
Brice Roncace
6

Я понимаю, что этот вопрос и ответы на него очень старые. Но я оказался здесь. Возможно, другие тоже.

Если у вас есть доступ к коду веб-службы, которая возвращает 401. Просто измените службу, чтобы в этой ситуации возвращать 403 (Запрещено) вместо 401. Браузер не будет запрашивать учетные данные в ответ на 403. 403 - это правильный код для аутентифицированного пользователя, не авторизованного для определенного ресурса. Кажется, это ситуация ОП.

Из документа IETF на 403:

Сервер, который получает действительные учетные данные, которых недостаточно для получения доступа, должен ответить кодом состояния 403 (Запрещено).

Джим Рейнери
источник
4

В Mozilla этого можно добиться с помощью следующего сценария при создании объекта XMLHttpRequest:

xmlHttp=new XMLHttpRequest();
xmlHttp.mozBackgroundRequest = true;
xmlHttp.open("GET",URL,true,USERNAME,PASSWORD);
xmlHttp.send(null);

Вторая строка запрещает диалоговое окно ....

HNygard
источник
1
Похоже, что это ничего не делает в Firefox 2. Это приводит к ошибке безопасности DOM, NS_ERROR_DOM_SECURITY_ERR code 1000, в Firefox 3.
dgvid
2

Какую серверную технологию вы используете и какой продукт вы используете для аутентификации?

Поскольку браузер выполняет только свою работу, я считаю, что вам нужно изменить что-то на стороне сервера, чтобы не возвращать код состояния 401. Это можно сделать с помощью настраиваемых форм проверки подлинности, которые просто возвращают форму снова при сбое проверки подлинности.

jan.vdbergh
источник
2

В мире Mozilla установка для параметра mozBackgroundRequest XMLHttpRequest ( docs ) значения true подавляет эти диалоги и вызывает просто сбой запросов. Однако я не знаю, насколько хороша кроссбраузерная поддержка (в том числе, насколько хорошо качество информации об ошибках по этим неудавшимся запросам во всех браузерах).

Rkslice
источник
Префикс moz- подразумевает отсутствие кроссбраузерной поддержки (если вы не можете найти похожие параметры, которые работают в каждом из других браузеров).
Brilliand
2

jan.vdbergh говорит правду: если вы можете изменить 401 на стороне сервера на другой код состояния, браузер не поймает и не раскрасит всплывающее окно. Другим решением может быть изменение заголовка WWW-Authenticate для другого настраиваемого заголовка. Я не верю, почему другой браузер не может его поддерживать, в нескольких версиях Firefox мы можем выполнить запрос xhr с помощью mozBackgroundRequest, но в других браузерах ?? здесь есть интересная ссылка на эту проблему в Chromium.

Каламарико
источник
1

У меня такая же проблема с MVC 5 и VPN, где всякий раз, когда мы находимся за пределами DMZ с помощью VPN, нам приходится отвечать на это сообщение браузера. Используя .net, я просто обрабатываю маршрутизацию ошибки, используя

<customErrors defaultRedirect="~/Error"  >
  <error statusCode="401" redirect="~/Index"/>
</customErrors>

до сих пор это работало, потому что действие Index в домашнем контроллере проверяет пользователя. Представление в этом действии, если вход в систему завершился неудачно, имеет элементы управления входом, которые я использую для входа пользователя в систему с использованием запроса LDAP, переданного в службы каталогов:

      DirectoryEntry entry = new DirectoryEntry("LDAP://OurDomain");
      DirectorySearcher Dsearch = new DirectorySearcher(entry);
      Dsearch.Filter = "(SAMAccountName=" + UserID + ")";
      Dsearch.PropertiesToLoad.Add("cn");

Хотя до сих пор это работало нормально, и я должен сообщить вам, что я все еще тестирую его, и у приведенного выше кода не было причин для запуска, поэтому он подлежит удалению ... тестирование в настоящее время включает в себя попытку обнаружить случай, когда второй набор кода больше пригодится. Опять же, это работа в стадии разработки, но так как это может быть некоторая помощь или подтолкнуть ваш мозг к некоторым идеям, я решил добавить его сейчас ... Я обновлю его окончательными результатами, когда все тестирование будет завершено.

Кларенс
источник
1

Я использую Node, Express и Passport и борюсь с той же проблемой. Я заставил его работать, явно установив www-authenticateзаголовок в пустую строку. В моем случае это выглядело так:

(err, req, res, next) => {
  if (err) {
    res._headers['www-authenticate'] = ''
    return res.json(err)
  }
}

Надеюсь, это кому-то поможет!

Джон Ноттс
источник
0

Для тех, кто не использует C #, здесь, ActionAttributeчто возвращается 400вместо 401и «проглатывает» диалог базовой аутентификации.

public class NoBasicAuthDialogAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);
        filterContext.Result = new HttpStatusCodeResult(400);
    }
}

используйте как следующее:

[NoBasicAuthDialogAuthorize(Roles = "A-Team")]
public ActionResult CarType()
{
 // your code goes here
}

Надеюсь, это сэкономит вам время.

Матас Вайткявичюс
источник