Мне нужно отправить запрос авторизации, используя базовый auth. Я успешно реализовал это с помощью jquery. Однако, когда я получаю сообщение об ошибке 401, открывается всплывающее окно auth browser и не вызывается обратный вызов jQuery ajax.
Как запретить браузеру вызывать базовое всплывающее окно auth и обрабатывать ошибку 401 с помощью JQuery?
Ответ 1
Я тоже недавно столкнулся с этой проблемой. Поскольку вы не можете изменить поведение браузера по умолчанию при отображении всплывающего окна в случае 401
(обычная или дайджест-проверка подлинности), есть два способа исправить это:
- Измените ответ сервера, чтобы не возвращать
401
. Вместо этого верните код200
и обработайте его в своем клиенте jQuery. -
Измените метод, который вы используете для авторизации, на пользовательское значение в вашем заголовке. Браузеры отобразят всплывающие окна для Basic и Digest. Вы должны изменить это как на клиенте, так и на сервере.
headers : { "Authorization" : "BasicCustom" }
Обратите также внимание на это для примера использования JQuery с базовой аутентификацией.
Ответ 2
Возвращает общий код состояния 400, а затем обрабатывает его на стороне клиента.
Или вы можете сохранить 401 и не возвращать заголовок WWW-Authenticate, на который браузер отвечает всплывающим окном аутентификации. Если заголовок WWW-Authenticate отсутствует, браузер не будет запрашивать учетные данные.
Ответ 3
Вы можете подавить базовое всплывающее окно с запросом url, выглядящим следующим образом:
https://username:[email protected]/admin/...
Если вы получите ошибку 401 (неправильное имя пользователя или пароль), она будет корректно обработана с помощью обратного вызова ошибки jquery. Это может вызвать некоторые проблемы с безопасностью (в случае HTTP-протокола вместо https), но он работает.
UPD: Поддержка этого решения будет удалена в Chrome 59
Ответ 4
Как указывали другие, единственный способ изменить поведение браузера - убедиться, что ответ либо не содержит код состояния 401, либо, если он есть, не включает заголовок WWW-Authenticate: Basic
. Поскольку изменение кода состояния не очень семантично и нежелательно, хорошим подходом является удаление заголовка WWW-Authenticate
. Если вы не можете или не хотите изменять приложение веб-сервера, вы всегда можете обслуживать или прокси-сервер через Apache (если вы еще не используете Apache).
Вот конфигурация для Apache для перезаписи ответа на удаление заголовка IFF-Authenticate IFF, содержащего запрос содержит заголовок X-Requested-With: XMLHttpRequest
(который по умолчанию задается основными фреймворками Javascript, такими как JQuery/AngularJS и т.д.). ) И ответ содержит заголовок WWW-Authenticate: Basic
.
Протестировано на Apache 2.4 (не уверен, работает ли оно с 2.2).
Это зависит от установленного модуля mod_headers
.
(В Debian/Ubuntu, sudo a2enmod headers
и перезапустите Apache)
<Location />
# Make sure that if it is an XHR request,
# we don't send back basic authentication header.
# This is to prevent the browser from displaying a basic auth login dialog.
Header unset WWW-Authenticate "expr=req('X-Requested-With') == 'XMLHttpRequest' && resp('WWW-Authenticate') =~ /^Basic/"
</Location>
Ответ 5
Если вы используете сервер IIS, вы можете настроить перезапись URL IIS (v2), чтобы перезаписать заголовок WWW-Authentication
на None
в запрошенном URL.
Значение, которое вы хотите изменить, это response_www_authenticate
.
Если вам нужна дополнительная информация, добавьте комментарий, и я опубликую файл web.config.
Ответ 6
Используйте X-Requested-With: XMLHttpRequest с вашим заголовком запроса. Таким образом, заголовок ответа не будет содержать WWW-Authenticate: Basic.
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', ("Basic "
.concat(btoa(key))));
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
},
Ответ 7
В качестве альтернативы, если вы можете настроить ответ своего сервера, вы можете вернуть 403 Запрещено.
Браузер не откроет всплывающее окно аутентификации, и будет вызван обратный вызов jquery.
Ответ 8
Если заголовок WWW-Authenticate удален, тогда вы не получите кэширование учетных данных и не получите обратно заголовок авторизации в запросе. Это означает, что теперь вам нужно будет ввести учетные данные для каждого нового запроса, который вы создаете.
Ответ 9
В Safari вы можете использовать синхронные запросы, чтобы браузер не отображал всплывающее окно. Конечно, синхронные запросы должны использоваться только в этом случае, чтобы проверять учетные данные пользователя... Вы можете использовать такой запрос перед отправкой фактического запроса, который может вызвать плохой пользовательский опыт, если контент (отправленный или полученный) довольно тяжелый.
var xmlhttp=new XMLHttpRequest;
xmlhttp.withCredentials=true;
xmlhttp.open("POST",<YOUR UR>,false,username,password);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
Ответ 10
Сделайте URL-адрес/login, а не принимайте параметры "пользователь" и "пароль" через GET и не требуйте базового auth. Здесь используйте php, node, java, что угодно, и проанализируйте свой файл passwd и сопоставьте параметры (пользователь/пропуск) с ним. Если есть совпадение, переадресовывайтесь на http://user:[email protected]/ (это установит учетные данные в вашем браузере), если нет, отправьте ответ 401 (без WWW-аутентификации заголовок).
Ответ 11
С обратной стороны с Spring Boot я использовал обычную BasicAuthenticationEntryPoint:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().authorizeRequests()
...
.antMatchers(PUBLIC_AUTH).permitAll()
.and().httpBasic()
// https://www.baeldung.com/spring-security-basic-authentication
.authenticationEntryPoint(authBasicAuthenticationEntryPoint())
...
@Bean
public BasicAuthenticationEntryPoint authBasicAuthenticationEntryPoint() {
return new BasicAuthenticationEntryPoint() {
{
setRealmName("pirsApp");
}
@Override
public void commence
(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
throws IOException, ServletException {
if (request.getRequestURI().equals(PUBLIC_AUTH)) {
response.sendError(HttpStatus.PRECONDITION_FAILED.value(), "Wrong credentials");
} else {
super.commence(request, response, authEx);
}
}
};
}