Использовать базовую аутентификацию с JQuery и Ajax

419

Я пытаюсь создать базовую аутентификацию через браузер, но я не могу туда добраться.

Если этот скрипт не будет здесь, аутентификация браузера вступит во владение, но я хочу сказать браузеру, что пользователь собирается сделать аутентификацию.

Адрес должен быть примерно таким:

http://username:password@server.in.local/

У меня есть форма:

<form name="cookieform" id="login" method="post">
      <input type="text" name="username" id="username" class="text"/>
      <input type="password" name="password" id="password" class="text"/>
      <input type="submit" name="sub" value="Submit" class="page"/>
</form>

И скрипт:

var username = $("input#username").val();
var password = $("input#password").val();

function make_base_auth(user, password) {
  var tok = user + ':' + password;
  var hash = Base64.encode(tok);
  return "Basic " + hash;
}
$.ajax
  ({
    type: "GET",
    url: "index1.php",
    dataType: 'json',
    async: false,
    data: '{"username": "' + username + '", "password" : "' + password + '"}',
    success: function (){
    alert('Thanks for your comment!');
    }
});
Patrioticcow
источник
6
То есть вы не хотите, чтобы браузер обрабатывал основную аутентификацию? Почему бы просто не использовать аутентификацию на основе форм?
no.good.at.coding
@ no.good.at.coding Если вам нужна интеграция с сторонним API за аутентификацией (что я и пытаюсь сделать - developer.zendesk.com/rest_api/docs/core/… )
Брайан Ханне

Ответы:

467

Используйте beforeSendобратный вызов jQuery для добавления заголовка HTTP с информацией аутентификации:

beforeSend: function (xhr) {
    xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},
ggarber
источник
6
Я использую приведенный вами пример, но он не работает `$ .ajax ({url:" server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader (" Авторизация "," Базовый ”+ EncodeBase64 (« username: password »));}, succes: function (val) {// alert (val); alert (« Спасибо за ваш комментарий! »);}}); `
Patrioticcow
69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };работает для меня
Рико Сутер
12
Проблема ... Если учетные данные, которые я передаю, не срабатывают, в Chrome пользователю затем предоставляется диалоговое окно для повторного ввода имени пользователя / pwd. Как я могу предотвратить появление этого 2-го диалога, если учетные данные не пройдены?
Дэвид
2
Разве это не оставит имя пользователя и пароль открытыми для просмотра? Даже если это в base64, они могут просто декодировать его. То же самое с ответом ниже.
cbron
6
@calebB Обычная аутентификация в общем просто оставляет имя пользователя и пароль открытыми для всех. Это не просто проблема с методом, описанным здесь. Если используется базовая аутентификация или действительно какая-либо аутентификация, то следует также использовать SSL.
Джейсон Джексон
354

Как все меняется за год. В дополнение к атрибуту header вместо xhr.setRequestHeaderтекущего jQuery (1.7.2+) включает в себя атрибут имени пользователя и пароля с $.ajaxвызовом.

$.ajax
({
  type: "GET",
  url: "index1.php",
  dataType: 'json',
  username: username,
  password: password,
  data: '{ "comment" }',
  success: function (){
    alert('Thanks for your comment!'); 
  }
});

РЕДАКТИРОВАТЬ из комментариев и других ответов: Для ясности - для приоритетной отправки аутентификации без 401 Unauthorizedответа вместо setRequestHeader(до -1.7) используйте 'headers':

$.ajax
({
  type: "GET",
  url: "index1.php",
  dataType: 'json',
  headers: {
    "Authorization": "Basic " + btoa(USERNAME + ":" + PASSWORD)
  },
  data: '{ "comment" }',
  success: function (){
    alert('Thanks for your comment!'); 
  }
});
jmanning2k
источник
15
Не должно быть usernameи нет user? Кроме того, это не совсем то же самое: из онлайн-документации и из моего опыта, похоже, что это не является преимуществом, как того требуют некоторые API. Другими словами, он отправляет Authorizationзаголовок только тогда, когда возвращается код 401.
Стефано Фратини
3
@StefanoFratini - вы правы в обоих случаях. Исправлено поле имени пользователя, и полезно знать о преимущественной аутентификации против ответа только на вызов. Установка заголовка явно, как и в других ответах, позволит использовать этот «пассивный» вариант базовой аутентификации.
jmanning2k
для меня вышеупомянутый вариант не работал, это работало как очарование .. спасибо
Anoop Исаак
См. Комментарий выше, пожалуйста, исправьте этот ответ, указав {"Авторизация": "Basic" + btoa ("user: pass")} в качестве правильного заголовка
Jay
2
Это ответ, который я искал! Ключевой бит в этом ответе для меня - то, как заголовок используется для упреждающей отправки аутентификации. Мой вопрос здесь ответил этим. stackoverflow.com/questions/28404452/…
Стивен Андерсон
63

Используйте обратный вызов beforeSend для добавления HTTP-заголовка с информацией аутентификации, например:

var username = $("input#username").val();
var password = $("input#password").val();  

function make_base_auth(user, password) {
  var tok = user + ':' + password;
  var hash = btoa(tok);
  return "Basic " + hash;
}
$.ajax
  ({
    type: "GET",
    url: "index1.php",
    dataType: 'json',
    async: false,
    data: '{}',
    beforeSend: function (xhr){ 
        xhr.setRequestHeader('Authorization', make_base_auth(username, password)); 
    },
    success: function (){
        alert('Thanks for your comment!'); 
    }
});
Адриан Томан
источник
4
Вы должны заметить, что «btoa», используемый здесь для шифрования Base64, не поддерживается в версиях IE менее 10 и на некоторых мобильных платформах
SET
1
также, согласно этому developer.mozilla.org/en-US/docs/DOM/window.btoa, вы должны использовать btoa (unescape (encodeURIComponent (str)))
SET
@SET, я думаю, это должно быть btoa (encodeURIComponent (escape (str)))
Саураб Кумар
Я хотел получить ответ, поэтому избавился от асинхронного false и добавил параметр результата в функцию успеха. У меня также был предварительно сгенерированный заголовок авторизации, поэтому я использовал его.
Радтек,
1
Следует отметить @SET, Base64 - это не шифрование, это кодировка. Если бы это было шифрование, было бы не просто расшифровать его с помощью одного вызова функции
Chris
40

Или просто используйте свойство headers, введенное в 1.5:

headers: {"Authorization": "Basic xxxx"}

Ссылка: jQuery Ajax API

AsemRadhwi
источник
Подскажите, пожалуйста, как это сделать для каждого пользователя? Я имею в виду получить токен API для каждого пользователя из базы данных и отправить его с заголовком ajax.
Хание Шадман
32

Приведенные выше примеры немного сбивают с толку, и это, вероятно, лучший способ:

$.ajaxSetup({
  headers: {
    'Authorization': "Basic " + btoa(USERNAME + ":" + PASSWORD)
  }
});

Я взял вышесказанное из комбинации ответа Рико и Йосси.

Btoa функция Base64 кодирует строку.

Пол Одеон
источник
5
Это плохая идея, потому что вы будете отправлять информацию для входа со всеми AJAX-запросами, независимо от URL. Кроме того , документация $.ajaxSetup()говорит «Установить значения по умолчанию для будущих запросов Ajax. Его использование не рекомендуется. »
ZERO3
27

Как и другие, вы можете установить имя пользователя и пароль непосредственно в вызове Ajax:

$.ajax({
  username: username,
  password: password,
  // ... other parameters.
});

ИЛИ используйте свойство headers, если вы не хотите хранить свои учетные данные в виде простого текста:

$.ajax({
  headers: {"Authorization": "Basic xxxx"},
  // ... other parameters.
});

Какой бы способ вы ни отправили, сервер должен быть очень вежливым. Для Apache ваш файл .htaccess должен выглядеть примерно так:

<LimitExcept OPTIONS>
    AuthUserFile /path/to/.htpasswd
    AuthType Basic
    AuthName "Whatever"
    Require valid-user
</LimitExcept>

Header always set Access-Control-Allow-Headers Authorization
Header always set Access-Control-Allow-Credentials true

SetEnvIf Origin "^(.*?)$" origin_is=$0
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

Объяснение:

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

Затем отправьте несколько заголовков, чтобы сообщить браузеру, что ему разрешено выполнять аутентификацию, и Access-Control-Allow-Origin, чтобы предоставить разрешение для межсайтового запроса.

В некоторых случаях подстановочный знак * не работает в качестве значения для Access-Control-Allow-Origin: вам необходимо вернуть точный домен вызываемого. Используйте SetEnvIf для захвата этого значения.

SharkAlley
источник
5
Спасибо за информацию, что браузеры отправляют предварительный запрос CORS без заголовков аутентификации! Такие детали могут привести к часам отладки!
jbandi
23

Используйте функцию jQuery ajaxSetup , которая может устанавливать значения по умолчанию для всех запросов ajax.

$.ajaxSetup({
  headers: {
    'Authorization': "Basic XXXXX"
  }
});
Йосси Шашо
источник
11

JSONP не работает с базовой аутентификацией, поэтому обратный вызов jQuery beforeSend не будет работать с JSONP / Script.

Мне удалось обойти это ограничение, добавив в запрос имя пользователя и пароль (например, user: pw@domain.tld). Это работает практически с любым браузером, кроме Internet Explorer, где аутентификация через URL не поддерживается (вызов просто не будет выполнен).

См. Http://support.microsoft.com/kb/834489 .

arnebert
источник
думаю, что в
плане
Ссылка не работает (404).
Питер Мортенсен
10

Есть 3 способа добиться этого, как показано ниже

Способ 1:

var uName="abc";
var passwrd="pqr";

$.ajax({
    type: '{GET/POST}',
    url: '{urlpath}',
    headers: {
        "Authorization": "Basic " + btoa(uName+":"+passwrd);
    },
    success : function(data) {
      //Success block  
    },
   error: function (xhr,ajaxOptions,throwError){
    //Error block 
  },
});

Способ 2:

var uName="abc";
var passwrd="pqr";

$.ajax({
    type: '{GET/POST}',
    url: '{urlpath}',
     beforeSend: function (xhr){ 
        xhr.setRequestHeader('Authorization', "Basic " + btoa(uName+":"+passwrd)); 
    },
    success : function(data) {
      //Success block 
   },
   error: function (xhr,ajaxOptions,throwError){
    //Error block 
  },
});

Способ 3:

var uName="abc";
var passwrd="pqr";

$.ajax({
    type: '{GET/POST}',
    url: '{urlpath}',
    username:uName,
    password:passwrd, 
    success : function(data) {
    //Success block  
   },
    error: function (xhr,ajaxOptions,throwError){
    //Error block 
  },
});
GSB
источник
8

Согласно ответу SharkAlley, он работает и с nginx.

Я искал решение для получения данных с помощью jQuery с сервера, расположенного за nginx и ограниченного Base Auth. Это работает для меня:

server {
    server_name example.com;

    location / {
        if ($request_method = OPTIONS ) {
            add_header Access-Control-Allow-Origin "*";
            add_header Access-Control-Allow-Methods "GET, OPTIONS";
            add_header Access-Control-Allow-Headers "Authorization";

            # Not necessary
            #            add_header Access-Control-Allow-Credentials "true";
            #            add_header Content-Length 0;
            #            add_header Content-Type text/plain;

            return 200;
        }

        auth_basic "Restricted";
        auth_basic_user_file /var/.htpasswd;

        proxy_pass http://127.0.0.1:8100;
    }
}

И код JavaScript:

var auth = btoa('username:password');
$.ajax({
    type: 'GET',
    url: 'http://example.com',
    headers: {
        "Authorization": "Basic " + auth
    },
    success : function(data) {
    },
});

Статья, которую я считаю полезной:

  1. Ответы этой темы
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
Maks
источник