Verwenden Sie die Basisauthentifizierung mit jQuery und Ajax


419

Ich versuche, eine grundlegende Authentifizierung über den Browser zu erstellen, komme aber nicht wirklich dorthin.

Wenn dieses Skript nicht hier ist, übernimmt die Browserauthentifizierung, aber ich möchte dem Browser mitteilen, dass der Benutzer die Authentifizierung durchführen wird.

Die Adresse sollte ungefähr so ​​lauten:

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

Ich habe ein Formular:

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

Und ein Drehbuch:

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!');
    }
});

6
Sie möchten also nicht, dass der Browser die BASIC-Authentifizierung übernimmt? Warum nicht einfach die formularbasierte Authentifizierung verwenden?
no.good.at.coding

@ no.good.at.coding Wenn Sie hinter der Authentifizierung eine API eines Drittanbieters integrieren müssen (was ich versuche - developer.zendesk.com/rest_api/docs/core/… )
Brian Hannay

Antworten:


466

Verwenden Sie den beforeSendRückruf von jQuery , um einen HTTP-Header mit den Authentifizierungsinformationen hinzuzufügen:

beforeSend: function (xhr) {
    xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},

6
Ich verwende das Beispiel, das du gegeben hast, aber es funktioniert nicht. $ .ajax ({url: " server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader ("Authorization", "Basic" ”+ EncodeBase64 (“ Benutzername: Passwort ”));}, Erfolg: Funktion (val) {// alert (val); alert (" Danke für Ihren Kommentar! ");}}); `
Patrioticcow

69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };arbeitet für mich
Rico Suter

12
Problem ... Wenn die von mir übergebenen Anmeldeinformationen fehlschlagen, wird dem Benutzer in Chrome ein Dialogfeld zur erneuten Eingabe von Benutzername / pwd angezeigt. Wie kann ich verhindern, dass dieser zweite Dialog angezeigt wird, wenn die Anmeldeinformationen fehlschlagen?
David

2
Wird dies nicht dazu führen, dass der Benutzername und das Passwort für niemanden sichtbar sind? Selbst wenn es in base64 ist, können sie es einfach dekodieren. Gleiches gilt für die Antwort unten.
Cbron

6
@calebB Die Standardauthentifizierung im Allgemeinen lässt nur den Benutzernamen und das Passwort offen, damit jeder sie sehen kann. Dies ist nicht nur ein Problem mit der hier beschriebenen Methode. Wenn eine Basisauthentifizierung oder wirklich eine Authentifizierung verwendet wird, sollte auch SSL verwendet werden.
Jason Jackson

354

Wie sich die Dinge in einem Jahr ändern. Zusätzlich zum Header-Attribut anstelle von enthält die xhr.setRequestHeaderaktuelle jQuery (1.7.2+) ein Benutzername- und Kennwortattribut mit dem $.ajaxAufruf.

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

BEARBEITEN von Kommentaren und anderen Antworten: Um klar zu sein - um die Authentifizierung präventiv ohne 401 UnauthorizedAntwort zu senden , anstatt setRequestHeader(vor -1,7) zu verwenden 'headers':

$.ajax
({
  type: "GET",
  url: "index1.php",
  dataType: 'json',
  headers: {
    "Authorization": "Basic " + btoa(USERNAME + ":" + PASSWORD)
  },
  data: '{ "comment" }',
  success: function (){
    alert('Thanks for your comment!'); 
  }
});

15
Sollte es nicht sein usernameund nicht user? Es ist auch nicht genau dasselbe: Aus den Online-Dokumenten und meiner Erfahrung nach sieht es so aus, als ob es nicht präventiv ist, wie es einige APIs erfordern. Mit anderen Worten, es sendet den AuthorizationHeader nur, wenn ein Code 401 zurückgegeben wird.
Stefano Fratini

3
@StefanoFratini - Sie sind in beiden Punkten korrekt. Das Feld für den Benutzernamen wurde korrigiert, und es ist gut, über die präemptive Authentifizierung Bescheid zu wissen, anstatt nur auf eine Herausforderung zu antworten. Wenn Sie den Header explizit wie in anderen Antworten festlegen, können Sie diese 'passive' Variante der Basisauthentifizierung verwenden.
jmanning2k

Für mich hat die oben genannte Option nicht funktioniert, dies hat wie ein Zauber funktioniert. Danke
Anoop Isaac

Siehe obigen Kommentar, bitte korrigieren Sie diese Antwort, um {"Authorization": "Basic" + btoa ("user: pass")} als korrekten Header anzugeben
Jay

2
Dies ist die Antwort, nach der ich gesucht habe! Das Schlüsselelement in dieser Antwort ist für mich, wie der 'Header' verwendet wird, um die Authentifizierung vorab zu senden. Meine Frage hier wird damit beantwortet. stackoverflow.com/questions/28404452/…
Steven Anderson

63

Verwenden Sie den beforeSend-Rückruf , um einen HTTP-Header mit folgenden Authentifizierungsinformationen hinzuzufügen:

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
Sie sollten beachten, dass "btoa", das hier für die Base64-Verschlüsselung verwendet wird, in IE-Versionen unter 10 und auf einigen mobilen Plattformen nicht unterstützt wird
SET

1
Laut diesem developer.mozilla.org/en-US/docs/DOM/window.btoa sollten Sie außerdem btoa (unescape (encodeURIComponent (str))) verwenden
SET

@ SET, ich denke, es muss btoa sein (encodeURIComponent (Escape (str)))
Saurabh Kumar

Ich wollte die Antwort erhalten, um async false zu entfernen, und fügte der Erfolgsfunktion den Ergebnisparameter hinzu. Ich hatte auch einen vorgenerierten Autorisierungsheader, also habe ich diesen stattdessen verwendet.
Radtek

1
@SET ist zu beachten, dass Base64 keine Verschlüsselung ist, sondern verschlüsselt. Wenn es Verschlüsselung wäre, wäre es nicht super einfach, es mit einem einzigen Funktionsaufruf zu dekodieren
Chris

40

Oder verwenden Sie einfach die in 1.5 eingeführte Eigenschaft headers:

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

Referenz: jQuery Ajax API


Würden Sie mir bitte sagen, wie es für jeden Benutzer geht? Ich meine, holen Sie sich ein API-Token für jeden Benutzer aus der Datenbank und senden Sie es mit einem Ajax-Header.
Haniye Shadman

32

Die obigen Beispiele sind etwas verwirrend, und dies ist wahrscheinlich der beste Weg:

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

Ich habe das Obige einer Kombination aus Rico und Yossis Antwort entnommen.

Die btoa- Funktion Base64 codiert eine Zeichenfolge.


5
Dies ist eine schlechte Idee, da Sie die Anmeldeinformationen mit allen AJAX-Anforderungen unabhängig von der URL senden . Außerdem heißt es in der Dokumentation zu $.ajaxSetup()"Festlegen von Standardwerten für zukünftige Ajax-Anforderungen. Die Verwendung wird nicht empfohlen. "
Zero3

27

Wie andere vorgeschlagen haben, können Sie den Benutzernamen und das Passwort direkt im Ajax-Aufruf festlegen:

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

ODER verwenden Sie die Eigenschaft headers, wenn Sie Ihre Anmeldeinformationen lieber nicht im Klartext speichern möchten:

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

Unabhängig davon, wie Sie es senden, muss der Server sehr höflich sein. Für Apache sollte Ihre .htaccess-Datei ungefähr so ​​aussehen:

<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

Erläuterung:

Bei einigen domänenübergreifenden Anforderungen sendet der Browser eine Preflight- OPTIONS- Anforderung, bei der Ihre Authentifizierungsheader fehlen. Wickeln Sie Ihre Authentifizierungsanweisungen in das LimitExcept- Tag ein, um ordnungsgemäß auf den Preflight zu reagieren.

Senden Sie dann einige Header, um dem Browser mitzuteilen, dass er sich authentifizieren darf, und die Zugriffssteuerung , die Origin zulässt , um die Berechtigung für die standortübergreifende Anforderung zu erteilen.

In einigen Fällen funktioniert der Platzhalter * nicht als Wert für Access-Control-Allow-Origin: Sie müssen die genaue Domäne des Angerufenen zurückgeben. Verwenden Sie SetEnvIf, um diesen Wert zu erfassen.


5
Vielen Dank für die Information, dass Browser eine CORS-Preflight-Anfrage ohne Auth-Header senden! Details wie diese können stundenlanges Debuggen verursachen!
Jbandi

23

Verwenden Sie die Funktion jQuery ajaxSetup , mit der Standardwerte für alle Ajax-Anforderungen festgelegt werden können.

$.ajaxSetup({
  headers: {
    'Authorization': "Basic XXXXX"
  }
});

11

JSONP funktioniert nicht mit der Basisauthentifizierung, sodass der Rückruf von jQuery beforeSend nicht mit JSONP / Script funktioniert.

Ich habe es geschafft, diese Einschränkung zu umgehen, indem ich der Anforderung den Benutzer und das Kennwort hinzugefügt habe (z. B. Benutzer: pw@domain.tld). Dies funktioniert mit so ziemlich jedem Browser außer Internet Explorer, in dem die Authentifizierung über URLs nicht unterstützt wird (der Aufruf wird einfach nicht ausgeführt).

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


Vermutlich ist es aus Sicherheitsgründen eine vernünftige Entscheidung, dies nicht zuzulassen
George Birbilis

Die Verbindung ist unterbrochen (404).
Peter Mortensen

10

Es gibt 3 Möglichkeiten, dies zu erreichen, wie unten gezeigt

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

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

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

8

Laut SharkAlley Antwort funktioniert es auch mit Nginx.

Ich suchte nach einer Lösung, um Daten von jQuery von einem Server hinter nginx abzurufen, der von Base Auth eingeschränkt wurde. Das funktioniert bei mir:

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

Und der JavaScript-Code lautet:

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

Artikel, den ich nützlich finde:

  1. Die Antworten dieses Themas
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.