Utiliser l'authentification de base avec jQuery et Ajax

419

J'essaie de créer une authentification de base via le navigateur, mais je n'y arrive pas vraiment.

Si ce script n'est pas là, l'authentification du navigateur prendra le relais, mais je veux dire au navigateur que l'utilisateur est sur le point de faire l'authentification.

L'adresse doit être quelque chose comme:

http://username:[email protected]/

J'ai un formulaire:

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

Et un script:

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!');
    }
});
Vache patriotique
la source
6
Vous ne voulez donc pas que le navigateur gère l'authentification BASIC? Pourquoi ne pas simplement utiliser l'authentification par formulaire?
no.good.at.coding
@ no.good.at.coding Si vous devez intégrer une API tierce derrière l'authentification (ce que j'essaie de faire - developer.zendesk.com/rest_api/docs/core/… )
Brian Hannay

Réponses:

467

Utilisez le beforeSendrappel de jQuery pour ajouter un en-tête HTTP avec les informations d'authentification:

beforeSend: function (xhr) {
    xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},
ggarber
la source
6
j'utilise l'exemple que vous avez donné mais cela ne fonctionne pas `$ .ajax ({url:" server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader (" Authorization "," Basic ”+ EncodeBase64 (“ nom d'utilisateur: mot de passe ”));}, succès: function (val) {// alert (val); alert (" Merci pour votre commentaire! ");}}); `
Patrioticcow
69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };travaille pour moi
Rico Suter
12
Problème ... Si les informations d'identification que je transmets échouent, dans Chrome, l'utilisateur est alors présenté avec une boîte de dialogue pour entrer à nouveau le nom d'utilisateur / pwd. Comment puis-je empêcher cette deuxième boîte de dialogue d'apparaître si les informations d'identification échouent?
David
2
Cela ne laissera-t-il pas le nom d'utilisateur et le mot de passe à la vue de tous? Même si c'est en base64, ils peuvent simplement le décoder. Même chose avec la réponse ci-dessous.
cbron
6
@calebB L'authentification de base en général laisse simplement le nom d'utilisateur et le mot de passe à la vue de tous. Ce n'est pas seulement un problème avec la méthode décrite ici. Si l'authentification de base, ou vraiment n'importe quelle authentification est utilisée, SSL doit également être utilisé.
Jason Jackson
354

Comment les choses changent en un an. En plus de l'attribut d'en-tête à la place de xhr.setRequestHeader, jQuery actuel (1.7.2+) inclut un attribut de nom d'utilisateur et de mot de passe avec l' $.ajaxappel.

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

MODIFIER à partir des commentaires et autres réponses: Pour être clair - afin d'envoyer de manière préventive l'authentification sans 401 Unauthorizedréponse, au lieu d' setRequestHeaderutiliser (avant -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
la source
15
Cela ne devrait-il pas l'être usernameet non user? De plus, ce n'est pas exactement la même chose: d'après les documents en ligne et mon expérience, il semble que ce ne soit pas préemptif comme certaines API le nécessitent. En d'autres termes, il n'envoie l'en- Authorizationtête que lorsqu'un code 401 est renvoyé.
Stefano Fratini
3
@StefanoFratini - vous avez raison sur les deux plans. Correction du champ du nom d'utilisateur, et il est bon de connaître l'authentification préemptive vs répondre uniquement en cas de défi. Définir l'en-tête explicitement comme dans les autres réponses permettra d'utiliser cette variante «passive» de l'authentification de base.
jmanning2k
pour moi l'option ci-dessus n'a pas fonctionné, cela a fonctionné comme un charme .. merci
Anoop Isaac
Voir le commentaire ci-dessus, veuillez corriger cette réponse pour indiquer {"Authorization": "Basic" + btoa ("user: pass")} comme en-tête correct
Jay
2
C'est la réponse que je cherchais! Pour moi, l'élément clé de cette réponse est de savoir comment l'en-tête est utilisé pour envoyer l'authentification de manière préventive. Ma question ici est répondue par ceci. stackoverflow.com/questions/28404452/…
Steven Anderson
63

Utilisez le rappel beforeSend pour ajouter un en-tête HTTP avec les informations d'authentification comme ceci:

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
la source
4
vous devez remarquer que "btoa" utilisé ici pour le chiffrement Base64 n'est pas pris en charge dans les versions IE inférieures à 10 et sur certaines plates
SET
1
également, selon ce developer.mozilla.org/en-US/docs/DOM/window.btoa, vous devez utiliser btoa (unescape (encodeURIComponent (str)))
SET
@SET, je suppose que cela doit être btoa (encodeURIComponent (escape (str)))
Saurabh Kumar
Je voulais obtenir la réponse, alors je me suis débarrassé de async false et j'ai ajouté le paramètre de résultat à la fonction de réussite. J'avais également un en-tête d'autorisation pré-généré, alors je l'ai utilisé à la place.
radtek
1
@SET est à noter que Base64 n'est pas du cryptage, c'est du codage. S'il s'agissait de chiffrement, il ne serait pas super simple de le décoder avec un seul appel de fonction
Chris
40

Ou, utilisez simplement la propriété headers introduite en 1.5:

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

Référence: API jQuery Ajax

AsemRadhwi
la source
Pourriez-vous me dire comment procéder pour chaque utilisateur? Je veux dire obtenir un jeton api pour chaque utilisateur de la base de données et l'envoyer avec l'en-tête ajax.
Haniye Shadman
32

Les exemples ci-dessus sont un peu déroutants, et c'est probablement la meilleure façon:

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

J'ai pris ce qui précède d'une combinaison de Rico et de la réponse de Yossi.

La fonction btoa Base64 code une chaîne.

Paul Odeon
la source
5
C'est une mauvaise idée, car vous enverrez les informations de connexion avec toutes les demandes AJAX, quelle que soit l'URL. En outre, la documentation de $.ajaxSetup()dit "Définir des valeurs par défaut pour les futures demandes Ajax. Son utilisation n'est pas recommandée. "
Zero3
27

Comme d'autres l'ont suggéré, vous pouvez définir le nom d'utilisateur et le mot de passe directement dans l'appel Ajax:

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

OU utilisez la propriété headers si vous préférez ne pas stocker vos informations d'identification en texte brut:

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

Quelle que soit la façon dont vous l'envoyez, le serveur doit être très poli. Pour Apache, votre fichier .htaccess devrait ressembler à ceci:

<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

Explication:

Pour certaines demandes interdomaines, le navigateur envoie une demande OPTIONS de contrôle en amont qui manque vos en-têtes d'authentification. Enveloppez vos directives d'authentification dans LimitExcept balise pour répondre correctement au contrôle en amont.

Envoyez ensuite quelques en-têtes pour indiquer au navigateur qu'il est autorisé à s'authentifier et à Access-Control-Allow-Origin d'accorder l'autorisation pour la demande intersite.

Dans certains cas, le caractère générique * ne fonctionne pas comme valeur pour Access-Control-Allow-Origin: vous devez renvoyer le domaine exact de l'appelé. Utilisez SetEnvIf pour capturer cette valeur.

SharkAlley
la source
5
Merci pour l'information que les navigateurs envoient une demande de contrôle en amont CORS sans en-têtes d'authentification! Des détails comme celui-ci peuvent entraîner des heures de débogage!
jbandi
23

Utilisez la fonction jQuery ajaxSetup , qui peut définir des valeurs par défaut pour toutes les demandes ajax.

$.ajaxSetup({
  headers: {
    'Authorization': "Basic XXXXX"
  }
});
Yossi Shasho
la source
11

JSONP ne fonctionne pas avec l'authentification de base, donc le rappel jQuery beforeSend ne fonctionnera pas avec JSONP / Script.

J'ai réussi à contourner cette limitation en ajoutant l'utilisateur et le mot de passe à la demande (par exemple utilisateur: [email protected]). Cela fonctionne avec à peu près n'importe quel navigateur sauf Internet Explorer où l'authentification via les URL n'est pas prise en charge (l'appel ne sera tout simplement pas exécuté).

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

arnebert
la source
devinez que sur le plan de la sécurité, c'est un choix sensé de ne pas autoriser cela
George Birbilis
Le lien est rompu (404).
Peter Mortensen
10

Il existe 3 façons d'y parvenir, comme indiqué ci-dessous

Méthode 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 
  },
});

Méthode 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 
  },
});

Méthode 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
la source
8

Selon la réponse de SharkAlley, cela fonctionne aussi avec nginx.

Je cherchais une solution pour obtenir des données par jQuery à partir d'un serveur derrière nginx et restreint par Base Auth. Cela fonctionne pour moi:

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

Et le code JavaScript est:

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

Article que je trouve utile:

  1. Réponses de ce sujet
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
Maks
la source