Używaj podstawowego uwierzytelniania w jQuery i Ajax

419

Próbuję utworzyć podstawowe uwierzytelnianie za pomocą przeglądarki, ale tak naprawdę nie mogę tego zrobić.

Jeśli skryptu tu nie będzie, uwierzytelnienie przeglądarki przejmie, ale chcę powiedzieć przeglądarce, że użytkownik zamierza dokonać uwierzytelnienia.

Adres powinien być podobny do:

http://username:[email protected]/

Mam formularz:

<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>

I skrypt:

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
źródło
6
Więc nie chcesz, aby przeglądarka obsługiwała uwierzytelnianie BASIC? Dlaczego nie skorzystać z uwierzytelniania opartego na formularzu?
no.good.at.coding
@ no.good.at.coding Jeśli chcesz zintegrować się z interfejsem API innej firmy odpowiedzialnym za uwierzytelnianie (co właśnie próbuję zrobić - developer.zendesk.com/rest_api/docs/core/… )
Brian Hannay

Odpowiedzi:

467

Użyj beforeSendwywołania zwrotnego jQuery, aby dodać nagłówek HTTP z informacjami uwierzytelniającymi:

beforeSend: function (xhr) {
    xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},
zrzędliwy
źródło
6
korzystam z przykładu, który podałeś, ale nie działa `$ .ajax ({url:" server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader („ Authorization ”,„ Basic ”+ EncodeBase64 („ nazwa użytkownika: hasło ”));}, succes: function (val) {// alert (val); alert („ Dziękujemy za komentarz! ”);}}); `
Patrioticcow
69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };działa dla mnie
Rico Suter
12
Problem ... Jeśli dane uwierzytelniające mi się nie udadzą, w Chrome użytkownikowi zostanie wyświetlone okno dialogowe umożliwiające ponowne wprowadzenie nazwy użytkownika / pwd. Jak mogę zapobiec wyświetlaniu drugiego okna dialogowego, jeśli referencje się nie udają?
David
2
Czy to nie pozostawia nazwy użytkownika i hasła otwartych dla nikogo do zobaczenia? Nawet jeśli jest w base64, mogą go po prostu odkodować. To samo z odpowiedzią poniżej.
cbron
6
@calebB Uwierzytelnianie podstawowe zasadniczo pozostawia nazwę użytkownika i hasło otwarte dla wszystkich. To nie jest tylko problem z opisaną tutaj metodą. Jeśli uwierzytelnianie podstawowe, czy naprawdę każdy uwierzytelniania jest używany wtedy należy również stosować SSL.
Jason Jackson
354

Jak rzeczy się zmieniają w ciągu roku. Oprócz atrybutu nagłówka zamiast xhr.setRequestHeaderbieżącego jQuery (1.7.2+) zawiera nazwę użytkownika i hasło do $.ajaxwywołania.

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

EDYCJA na podstawie komentarzy i innych odpowiedzi: Aby być jasnym - w celu prewencyjnego wysłania uwierzytelnienia bez 401 Unauthorizedodpowiedzi, zamiast setRequestHeader(przed -1.7) użyj '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
źródło
15
Nie powinno być usernamei nie user? Nie jest to dokładnie to samo: z internetowych dokumentów i z mojego doświadczenia wynika, że ​​nie jest to zapobiegawcze, jak wymagają niektóre interfejsy API. Innymi słowy, wysyła Authorizationnagłówek tylko wtedy, gdy zwracany jest kod 401.
Stefano Fratini,
3
@StefanoFratini - masz rację w obu kwestiach. Naprawiono pole nazwy użytkownika i dobrze jest wiedzieć o autorytatywnym uwierzytelnianiu vs reagowaniu tylko na wyzwanie. Jawne ustawienie nagłówka, tak jak w innych odpowiedziach, pozwoli na użycie tego „pasywnego” wariantu podstawowego uwierzytelnienia.
jmanning2k
dla mnie powyższa opcja nie zadziałała, działało to jak urok .. dzięki
Anoop Isaac
Patrz powyższy komentarz, popraw tę odpowiedź, aby wskazać {„Autoryzacja”: „Podstawowy” + btoa („użytkownik: hasło”)} jako prawidłowy nagłówek
Jay
2
Oto odpowiedź, na którą szukałem! Kluczem w tej odpowiedzi jest dla mnie sposób, w jaki „nagłówek” służy do prewencyjnego wysyłania uwierzytelnienia. Odpowiedzi na moje pytanie tutaj. stackoverflow.com/questions/28404452/…
Steven Anderson
63

Użyj wywołania zwrotnego beforeSend, aby dodać nagłówek HTTP z informacjami uwierzytelniającymi:

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!'); 
    }
});
Adrian Toman
źródło
4
powinieneś zauważyć, że „btoa” użyte tutaj do szyfrowania Base64 nie jest obsługiwane w wersjach IE mniejszych niż 10 i na niektórych platformach mobilnych
SET
1
Ponadto, zgodnie z tym developer.mozilla.org/en-US/docs/DOM/window.btoa , powinieneś użyć btoa (unescape (encodeURIComponent (str)))
SET
@SET, chyba to musi być btoa (encodeURIComponent (escape (str)))
Saurabh Kumar
Chciałem uzyskać odpowiedź, więc pozbyłem się asynchronicznego fałszu i dodałem parametr wyniku do funkcji sukcesu. Miałem również wstępnie wygenerowany nagłówek autoryzacji, więc właśnie go użyłem.
radtek
1
@SET należy zauważyć, że Base64 nie szyfruje, tylko koduje. Gdyby to było szyfrowanie, dekodowanie go za pomocą jednego wywołania funkcji nie byłoby super proste
Chris
40

Lub po prostu użyj właściwości nagłówków wprowadzonej w 1.5:

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

Odniesienie: jQuery Ajax API

AsemRadhwi
źródło
Czy możesz mi powiedzieć, jak to zrobić dla każdego użytkownika? Mam na myśli pobrać token api dla każdego użytkownika z bazy danych i wysłać go z nagłówkiem ajax.
Haniye Shadman
32

Powyższe przykłady są nieco mylące i jest to prawdopodobnie najlepszy sposób:

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

Wziąłem powyższe z kombinacji odpowiedzi Rico i Yossi.

Btoa funkcja Base64 koduje łańcuch.

Paul Odeon
źródło
5
To zły pomysł, ponieważ wyślesz dane logowania ze wszystkimi żądaniami AJAX, niezależnie od adresu URL. Ponadto dokumentacja $.ajaxSetup()mówi: „Ustaw wartości domyślne dla przyszłych żądań Ajax. Jego użycie nie jest zalecane.
Zero3
27

Jak sugerują inni, możesz ustawić nazwę użytkownika i hasło bezpośrednio w wywołaniu Ajax:

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

LUB użyj właściwości headers, jeśli nie chcesz przechowywać poświadczeń w postaci zwykłego tekstu:

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

Bez względu na to, jak go wyślesz, serwer musi być bardzo uprzejmy. W przypadku Apache plik .htaccess powinien wyglądać mniej więcej tak:

<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

Wyjaśnienie:

W przypadku niektórych żądań między domenami przeglądarka wysyła żądanie OPTIONS inspekcji wstępnej, w którym brakuje nagłówków uwierzytelniania. Zawiń dyrektywy uwierzytelniania w tagu LimitExcept, aby poprawnie reagować na inspekcję wstępną .

Następnie wyślij kilka nagłówków, aby poinformować przeglądarkę, że może się uwierzytelnić, a Access-Control-Allow-Origin, aby udzielić zgody na żądanie między witrynami.

W niektórych przypadkach symbol wieloznaczny * nie działa jako wartość kontroli dostępu-Allow-Origin: musisz zwrócić dokładną domenę odbiorcy. Użyj SetEnvIf, aby przechwycić tę wartość.

SharkAlley
źródło
5
Dziękujemy za informację, że przeglądarki wysyłają żądanie wstępnej inspekcji CORS bez nagłówków uwierzytelniania! Takie szczegóły mogą powodować godziny debugowania!
jbandi
23

Użyj funkcji jQuery ajaxSetup , która może ustawić wartości domyślne dla wszystkich żądań ajax.

$.ajaxSetup({
  headers: {
    'Authorization': "Basic XXXXX"
  }
});
Yossi Shasho
źródło
11

JSONP nie działa z podstawowym uwierzytelnianiem, więc wywołanie zwrotne jQuery beforeSend nie będzie działać z JSONP / Script.

Udało mi się obejść to ograniczenie, dodając do żądania użytkownika i hasło (np. Użytkownik: [email protected]). Działa to praktycznie z każdą przeglądarką oprócz Internet Explorera którym uwierzytelnianie za pomocą adresów URL nie jest obsługiwane (wywołanie po prostu nie zostanie wykonane).

Zobacz http://support.microsoft.com/kb/834489 .

Arnbert
źródło
zgadnij, że ze względów bezpieczeństwa rozsądnym wyborem jest niedopuszczenie do tego
George Birbilis,
Link jest zepsuty (404).
Peter Mortensen
10

Istnieją 3 sposoby osiągnięcia tego, jak pokazano poniżej

Metoda 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 
  },
});

Metoda 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 
  },
});

Metoda 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
źródło
8

Według odpowiedzi SharkAlley działa również z Nginx.

Szukałem rozwiązania w celu uzyskania danych przez jQuery z serwera za nginx i ograniczonego przez Base Auth. To działa dla mnie:

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;
    }
}

A kod JavaScript to:

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

Artykuł, który uważam za użyteczny:

  1. Odpowiedzi na ten temat
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
Maks
źródło