Як завадити браузеру викликати базове спливаюче вікно auth та обробляти помилку 401 за допомогою Jquery?


107

Мені потрібно надіслати запит на авторизацію, використовуючи базовий auth. Я успішно реалізував це за допомогою jquery. Однак, коли я отримую помилку 401, відкривається спливаюче вікно браузера auth, і зворотний виклик jquery ajax не викликається.


Відповіді:


46

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

  • Змініть відповідь сервера, щоб не повертати a 401. 200Натомість поверніть код і обробіть це у своєму клієнті jQuery.
  • Змініть метод, який ви використовуєте для авторизації, на спеціальне значення у своєму заголовку. Браузери відображатимуть спливаючі вікна для Basic та Digest . Ви повинні змінити це як на клієнті, так і на сервері.

    headers : {
      "Authorization" : "BasicCustom"
    }

Будь ласка, погляньте на це для прикладу використання jQuery з Basic Auth.


10
WWW-Authenticate: xBasic realm = com.example може це зробити разом з класичним кодом статусу 401. ця публікація в блозі показала мені підказку (я не є власником щоденника) Louvchar.blogspot.ca/2010/11/…
PM

2
@PM, відповідь блогу - ідеальне рішення. Зауважте, що для використання <security:http-basic/>вам не потрібно визначати, basicAuthenticationFilterале слід визначати як <security:http-basic entry-point-ref="myBasicAuthenticationEntryPoint"/>.
Бретт Райан

Чи можете ви сказати мені, як змінити відповідь, перш ніж надсилати клієнту, я використовую jaxrs з базовим auth. який клас мені потрібно змінити для зміни відповіді?
mohammed sameen

Чомусь я отримую спливаюче вікно при поверненні 401а, WWW-Authenticate:Bearer WWW-Authenticate:NTLM WWW-Authenticate:Negotiateчи знаєте ви, чому це було б?
DevEng

34

Поверніть загальний код 400 стану, а потім обробіть цей клієнт.

Або ви можете зберегти 401, а не повернути заголовк WWW-Authenticate, що насправді відповідає браузеру при спливаючому вікні аутентифікації. Якщо заголовок WWW-Authenticate відсутній, браузер не вимагатиме отримання облікових даних.


6
@MortenHaraldsen Ну відповідь 401 - це належна відповідь, яку потрібно надати з цього приводу. Проблема полягає в тому, що браузер автоматично справляється з цим власним чином, замість того, щоб програма javascript могла це обробити. Ви можете дотримуватися стандарту, не повертаючи належної відповіді, яку рекомендує стандарт, або ви можете не дотримуватися стандарту, повертаючи стандартний код відповіді. Візьміть свій вибір :)
Ibraheem

У своєму експрес-додатку я зафіксував це одним рядком: res.removeHeader('www-authenticate'); // prevents browser from popping up a basic auth window.
gstroup

1
@Ibraheem, я не міг би це заявити краще. Стандарти створюються людьми, які сідають і розмовляють, не обов'язково тими, хто сідає і кодує.
користувач2867288

15

Ви можете придушити основне спливаюче вікно аутентифікації з таким URL-адресом запиту:

https://username:password@example.com/admin/...

Якщо ви отримаєте помилку 401 (неправильне ім’я користувача або пароль), вона буде правильно оброблена зворотним зв'язком jquery error. Це може спричинити деякі проблеми із безпекою (у випадку протоколу http замість https), але це працює.

UPD: Підтримка цього рішення буде видалена в Chrome 59


ДИВОВИЖНИЙ!!!! Вирішив мою проблему, оскільки проблема намагалася 192.168.1.1, і маршрутизатор продовжував просити Auth.
Надав Лебович

Якщо ви перейдете на вкладку "Мережа" під інструментами розробника, у будь-якому браузері ви зможете прочитати ім'я користувача та пароль у простому тексті. Це працює, хоча.
Бруно Палець

19
Ніколи цього не робіть, будь ласка, журнали запитів на вашому веб-сервері зараз для мене набагато цінніші. Безкоштовні імена користувачів та пароль, а також код відповіді! Спасибі
Ремко

але як хтось може запобігти перегляду імені користувача та пароля
sdx11

3
Цей метод аутентифікації стає знеціненим, і Chrome буде припиняти підтримку вбудованих облікових даних, тобто https://user:pass@host/в M59, приблизно в червні 2017 року. Докладнішу інформацію див. У цьому блозі щодо хростату .
Garywoo

13

Як зазначали інші, єдиний спосіб змінити поведінку браузера - переконатися, що відповідь або не містить код стану 401, або, якщо він є, не містить WWW-Authenticate: Basicзаголовка. Оскільки зміна коду статусу не дуже смислова і небажана, хорошим підходом є видалення WWW-Authenticateзаголовка. Якщо ви не можете або не хочете змінювати свою програму веб-сервера, ви завжди можете обслуговувати або проксі-сервер через Apache (якщо ви вже не використовуєте Apache).

Ось конфігурація для Apache, щоб переписати відповідь на видалення заголовка WWW-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>   

1
Щоб зробити те ж саме з Nginx, встановітьproxy_hide_header WWW-Authenticate;
Cuga

7

Використовуйте X-Requested-With: XMLHttpRequest із заголовком запиту. Тож заголовок відповіді не буде містити WWW-Authenticate: Basic.

beforeSend: function (xhr) {
                    xhr.setRequestHeader('Authorization', ("Basic "
                        .concat(btoa(key))));
                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                },

1
Це не мало для мене ефекту. Який тип сервера ви використовуєте, що WWW-автентифікат не надсилається, коли ви встановлюєте XMLHttpRequest?
Роберт Антонучі

@RobertAntonucci це apache tomcat
sedhu

5

Якщо ви використовуєте сервер IIS, можна налаштувати IIS URL Переписуючи (v2) , щоб переписати WWW-Authenticationзаголовок Noneна запитаний URL.

Посібник тут .

Значення, яке ви хочете змінити response_www_authenticate.

Якщо вам потрібна додаткова інформація, додайте коментар, і я опублікую файл web.config.


1
Це вийшло чудово. Я хотів би зазначити, що частина "відповідь" повинна бути записана як "RESPONSE_www_authenticate" у URL-адресі Переписати v2 на IIS 7.5.
Майкл Фрімен

3

Якщо заголовок WWW-Authenticate видалено, ви не отримаєте кешування облікових даних і не зможете повернути заголовок авторизації у запиті. Це означає, що тепер вам доведеться вводити облікові дані для кожного нового генерованого вами запиту.


Це дуже важливо, абсолютно на місці.
Tez Вингфилд

2

Крім того, якщо ви можете налаштувати відповідь вашого сервера, ви можете повернути 403 Заборонено.

Браузер не відкриє спливаюче вікно аутентифікації, і буде викликано зворотний дзвінок jquery.


5
Це суперечить специфікації HTTP 1.1, де зазначено, що "... Авторизація не допоможе, і запит НЕ повинен повторюватися".
Jukka Dahlbom

1
Дійсно отримувати 403 під час автентифікації на ресурси, до яких ви не маєте доступу, 401 слід надсилати там, де ви ще не пройшли автентифікацію.
Бретт Райан

1

У 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');

В інших контекстах також може допомогти використання "OPTIONS" замість "POST".
Еммануель Сельєр

0

Створіть URL / login, ніж приймайте параметри "user" та "password" через GET і не вимагайте базових auth. Тут використовуйте php, node, java, що завгодно і проаналізуйте ваш passwd файл та порівняйте параметри (user / pass) проти нього. Якщо є відповідність, перенаправляйте на http: // user: pass@domain.com/ (якщо це встановить обліковий запис у вашому браузері), якщо ні, надішліть відповідь 401 (без заголовка WWW-Authenticate).


Це було б чудово для тих, хто намагається нюхати ім’я користувача / паролі з простого тексту в атаках посередині!
Аякс

0

Зі зворотного боку за допомогою 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);
            }
        }
    };
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.