Use autenticación básica con jQuery y Ajax


419

Estoy tratando de crear una autenticación básica a través del navegador, pero realmente no puedo llegar allí.

Si este script no está aquí, la autenticación del navegador se hará cargo, pero quiero decirle al navegador que el usuario está a punto de realizar la autenticación.

La dirección debería ser algo como:

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

Tengo un formulario:

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

Y un guión:

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

66
¿Entonces no quieres que el navegador maneje la autenticación BÁSICA? ¿Por qué no solo usar autenticación basada en formularios?
no.good.at.coding

@ no.good.at.coding Si necesita integrarse con una API de terceros detrás de la autenticación (que es lo que estoy tratando de hacer - developer.zendesk.com/rest_api/docs/core/… )
Brian Hannay

Respuestas:


467

Use la beforeSenddevolución de llamada de jQuery para agregar un encabezado HTTP con la información de autenticación:

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

66
Estoy usando el ejemplo que usted dio pero no funciona `$ .ajax ({url:" server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader (" Autorización "," Básico ”+ EncodeBase64 (“ nombre de usuario: contraseña ”));}, succes: function (val) {// alert (val); alert (" ¡Gracias por tu comentario! ");}}); `
Patrioticcow

69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };funciona para mí
Rico Suter

12
Problema ... Si las credenciales que paso fallan, en Chrome se le presenta al usuario un cuadro de diálogo para ingresar nuevamente nombre de usuario / pwd. ¿Cómo puedo evitar que este segundo diálogo aparezca si las credenciales fallan?
David

2
¿Esto no dejará el nombre de usuario y la contraseña a la vista de todos? Incluso si está en base64, solo pueden decodificarlo. Lo mismo con la respuesta a continuación.
cbron

66
@calebB La autenticación básica en general solo deja el nombre de usuario y la contraseña a la vista de todos. Esto no es solo un problema con el método descrito aquí. Si se está utilizando autenticación básica, o realmente se está utilizando cualquier autenticación, también se debe emplear SSL.
Jason Jackson

354

Cómo cambian las cosas en un año. Además del atributo de encabezado en lugar de xhr.setRequestHeader, jQuery actual (1.7.2+) incluye un atributo de nombre de usuario y contraseña con la $.ajaxllamada.

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

EDITAR a partir de comentarios y otras respuestas: Para ser claros, para enviar autenticación de forma preventiva sin una 401 Unauthorizedrespuesta, en lugar de setRequestHeader(pre -1.7) use '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
¿No debería ser usernamey no user? Además, no es exactamente lo mismo: de los docos en línea y mi experiencia parece que no es preventiva como requieren algunas API. En otras palabras, envía el Authorizationencabezado solo cuando se devuelve un código 401.
Stefano Fratini

3
@StefanoFratini: tienes razón en ambos aspectos. Se corrigió el campo de nombre de usuario, y es bueno saber acerca de la autenticación preventiva frente a responder solo en caso de desafío. Establecer el encabezado explícitamente como en otras respuestas permitirá el uso de esta variante 'pasiva' de autenticación básica.
jmanning2k

para mí la opción anterior no funcionó, esto funcionó de maravilla ... gracias
Anoop Isaac

Vea el comentario anterior, corrija esta respuesta para indicar {"Autorización": "Básico" + btoa ("usuario: pasar")} como el encabezado correcto
Jay

2
¡Esta es la respuesta que he estado buscando! La clave en esta respuesta para mí es cómo se usa el 'encabezado' para enviar la autenticación de manera preventiva. Mi pregunta aquí es respondida por esto. stackoverflow.com/questions/28404452/…
Steven Anderson

63

Use la devolución de llamada beforeSend para agregar un encabezado HTTP con la información de autenticación de esta manera:

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

44
debe tener en cuenta que "btoa" utilizado aquí para el cifrado Base64 no es compatible con versiones de IE inferiores a la 10 y en algunas plataformas móviles
SET

1
también, de acuerdo con este desarrollador.mozilla.org/en-US/docs/DOM/window.btoa , debe usar btoa (unescape (encodeURIComponent (str)))
SET

@SET, supongo que debe ser btoa (encodeURIComponent (escape (str)))
Saurabh Kumar

Quería obtener la respuesta, así que me deshice de async false y agregué el parámetro de resultado a la función de éxito. También tenía un encabezado de autorización pregenerado, así que solo lo usé en su lugar.
radtek

1
@SET se debe tener en cuenta que Base64 no es cifrado, es codificación. Si se tratara de cifrado, no sería muy sencillo decodificarlo con una sola llamada de función
Chris

40

O simplemente use la propiedad de encabezados introducida en 1.5:

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

Referencia: jQuery Ajax API


¿Podría decirme cómo hacerlo para cada usuario? Me refiero a obtener un token api para cada usuario de la base de datos y enviarlo con un encabezado ajax.
Haniye Shadman

32

Los ejemplos anteriores son un poco confusos, y esta es probablemente la mejor manera:

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

Tomé lo anterior de una combinación de la respuesta de Rico y Yossi.

La función btoa Base64 codifica una cadena.


55
Esta es una mala idea, ya que enviará la información de inicio de sesión con todas las solicitudes de AJAX, independientemente de la URL. Además, la documentación $.ajaxSetup()dice "Establecer valores predeterminados para futuras solicitudes de Ajax. No se recomienda su uso " .
Zero3

27

Como otros han sugerido, puede configurar el nombre de usuario y la contraseña directamente en la llamada Ajax:

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

O use la propiedad de encabezados si prefiere no almacenar sus credenciales en texto sin formato:

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

De cualquier forma que lo envíe, el servidor debe ser muy cortés. Para Apache, su archivo .htaccess debería verse así:

<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

Explicación:

Para algunas solicitudes de dominio cruzado, el navegador envía una solicitud de OPCIONES de verificación previa a la que le faltan los encabezados de autenticación. Envuelva sus directivas de autenticación dentro de la etiqueta LimitExcept para responder correctamente a la verificación previa.

Luego, envíe algunos encabezados para indicarle al navegador que tiene permiso para autenticarse y que Access-Control-Allow-Origin otorgue permiso para la solicitud entre sitios.

En algunos casos, el comodín * no funciona como un valor para Access-Control-Allow-Origin: debe devolver el dominio exacto de la persona que llama. Use SetEnvIf para capturar este valor.


55
¡Gracias por la información de que los navegadores envían una solicitud de verificación previa de CORS sin encabezados de autenticación! ¡Detalles como este pueden causar horas de depuración!
jbandi

23

Utilice la función jQuery ajaxSetup , que puede configurar valores predeterminados para todas las solicitudes de ajax.

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

11

JSONP no funciona con autenticación básica, por lo que la devolución de llamada jQuery beforeSend no funcionará con JSONP / Script.

Logré evitar esta limitación agregando el usuario y la contraseña a la solicitud (por ejemplo, usuario: pw@dominio.tld). Esto funciona con prácticamente cualquier navegador, excepto Internet Explorer, donde la autenticación a través de URL no es compatible (la llamada simplemente no se ejecutará).

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


supongo que, en cuanto a seguridad, es una buena opción no permitir esto
George Birbilis

El enlace está roto (404).
Peter Mortensen

10

Hay 3 formas de lograr esto como se muestra a continuación

Método 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étodo 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étodo 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

Según la respuesta de SharkAlley, también funciona con nginx.

Estaba buscando una solución para obtener datos mediante jQuery desde un servidor detrás de nginx y restringido por Base Auth. Esto funciona para mi:

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

Y el código JavaScript es:

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

Artículo que me parece útil:

  1. Las respuestas de este tema
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.