Use autenticação básica com jQuery e Ajax

419

Estou tentando criar uma autenticação básica através do navegador, mas não consigo chegar lá.

Se esse script não estiver aqui, a autenticação do navegador assumirá o controle, mas quero informar ao navegador que o usuário está prestes a fazer a autenticação.

O endereço deve ser algo como:

http://username:[email protected]/

Eu tenho um formulário:

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

E um 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!');
    }
});
Patrioticcow
fonte
6
Então você não quer que o navegador lide com a autenticação BASIC? Por que não usar apenas autenticação baseada em formulário?
no.good.at.coding
@ no.good.at.coding Se você precisar integrar-se a uma API de terceiros atrás da autenticação (que é o que estou tentando fazer - developer.zendesk.com/rest_api/docs/core/… )
Brian Hannay

Respostas:

467

Use o beforeSendretorno de chamada do jQuery para adicionar um cabeçalho HTTP com as informações de autenticação:

beforeSend: function (xhr) {
    xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},
ggarber
fonte
6
Estou usando o exemplo que você deu, mas ele não funciona `$ .ajax ({url:" server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader (“ Authorization ”,“ Basic ”+ EncodeBase64 (“ nome de usuário: senha ”));}, obtém: function (val) {// alert (val); alert (" Obrigado pelo seu comentário! ");}}); `
Patrioticcow
69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };funciona para mim #
Rico Suter
12
Problema ... Se as credenciais aprovadas falharem, no Chrome, o usuário receberá uma caixa de diálogo para inserir o nome de usuário / senha novamente. Como impedir que essa segunda caixa de diálogo apareça se as credenciais falharem?
David
2
Isso não deixará o nome de usuário e a senha em aberto para qualquer um ver? Mesmo que esteja na base64, eles podem apenas decodificá-lo. Mesmo com a resposta abaixo.
Cbron
6
@calebB A autenticação básica em geral apenas deixa o nome de usuário e a senha em aberto para qualquer um ver. Este não é apenas um problema com o método descrito aqui. Se a autenticação básica ou realmente qualquer autenticação estiver sendo usada, o SSL também deverá ser empregado.
Jason Jackson
354

Como as coisas mudam em um ano. Além do atributo de cabeçalho no lugar de xhr.setRequestHeader, o jQuery atual (1.7.2+) inclui um atributo de nome de usuário e senha na $.ajaxchamada.

$.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 comentários e outras respostas: Para ser claro - para enviar preventivamente a autenticação sem uma 401 Unauthorizedresposta, em vez de setRequestHeader(pré--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!'); 
  }
});
jmanning2k
fonte
15
Não deveria ser usernamee não user? Também não é exatamente o mesmo: pelos documentos on-line e pela minha experiência, parece que não é preventivo, como exigem algumas APIs. Em outras palavras, ele envia o Authorizationcabeçalho somente quando um código 401 é retornado.
Stefano Fratini
3
@StefanoFratini - você está correto nos dois aspectos. Corrigido o campo de nome de usuário, e é bom saber sobre a autenticação preventiva versus responder apenas no desafio. Definir o cabeçalho explicitamente como em outras respostas permitirá o uso dessa variante 'passiva' da autenticação básica.
precisa saber é o seguinte
para mim o acima opção não funcionava, isso funcionou como um encanto .. obrigado
Anoop Isaac
Veja acima comentário, por favor, corrija esta resposta para indicar { "Autorização": "Basic" + btoa ( "user: pass")} como o cabeçalho correto
Jay
2
Esta é a resposta que eu tenho procurado! O ponto chave nesta resposta para mim é como o 'cabeçalho' é usado para enviar a autenticação preventivamente. Minha pergunta aqui é respondida por isso. stackoverflow.com/questions/28404452/…
Steven Anderson
63

Use o retorno de chamada beforeSend para adicionar um cabeçalho HTTP com as informações de autenticação da seguinte maneira:

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
fonte
4
você deve observar que "btoa" usado aqui para criptografia Base64 não é suportado nas versões IE inferiores a 10 e em algumas plataformas móveis
SET
1
Além disso, de acordo com este developer.mozilla.org/pt-BR/docs/DOM/window.btoa, você deve usar o btoa (unescape (encodeURIComponent (str)))
SET
@SET, eu acho que ele precisa ser btoa (encodeURIComponent (escape (str)))
Saurabh Kumar
Eu queria obter a resposta, então me livrei do assíncrono falso e adicionei parâmetro de resultado à função de sucesso. Eu também tinha um cabeçalho de autorização pré-gerado, então apenas o usei.
radtek
1
O @SET deve ser observado: o Base64 não é criptografia, é codificação. Se fosse criptografia, não seria super simples para decodificá-lo com uma única chamada de função
Chris
40

Ou simplesmente use a propriedade headers introduzida na 1.5:

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

Referência: API do jQuery Ajax

AsemRadhwi
fonte
Você poderia me dizer como fazer isso para cada usuário? Quero dizer, obter o token de API para cada usuário do banco de dados e enviá-lo com o cabeçalho ajax.
Haniye Shadman 27/07/19
32

Os exemplos acima são um pouco confusos, e esta é provavelmente a melhor maneira:

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

Peguei o acima de uma combinação da resposta de Rico e Yossi.

A função btoa Base64 codifica uma sequência.

Paul Odeon
fonte
5
É uma péssima idéia, porque você enviará as informações de login com todas as solicitações AJAX, independentemente da URL. Além disso, a documentação para $.ajaxSetup()diz "Defina valores padrão para solicitações futuras do Ajax. Seu uso não é recomendado. "
Zero3
27

Como outros sugeriram, você pode definir o nome de usuário e a senha diretamente na chamada do Ajax:

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

OU use a propriedade headers se você preferir não armazenar suas credenciais em texto sem formatação:

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

Qualquer que seja a forma de envio, o servidor deve ser muito educado. Para o Apache, seu arquivo .htaccess deve ser algo assim:

<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

Explicação:

Para algumas solicitações de domínio cruzado, o navegador envia uma solicitação de OPTIONS de comprovação sem os cabeçalhos de autenticação. Coloque suas diretivas de autenticação dentro da marca LimitExcept para responder adequadamente à comprovação.

Em seguida, envie alguns cabeçalhos para informar ao navegador que ele pode se autenticar e o Access-Control-Allow-Origin para conceder permissão para a solicitação entre sites.

Em alguns casos, o curinga * não funciona como um valor para Access-Control-Allow-Origin: Você precisa retornar o domínio exato do chamado. Use SetEnvIf para capturar esse valor.

SharkAlley
fonte
5
Obrigado pela informação de que os navegadores enviam uma solicitação de comprovação CORS sem cabeçalhos de autenticação! Detalhes como esse podem causar horas de depuração!
jbandi
23

Use a função jQuery ajaxSetup , que pode configurar valores padrão para todas as solicitações de ajax.

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

O JSONP não funciona com autenticação básica, portanto, o retorno de chamada jQuery beforeSend não funcionará com JSONP / Script.

Consegui contornar essa limitação adicionando o usuário e a senha à solicitação (por exemplo, usuário: [email protected]). Isso funciona com praticamente qualquer navegador, exceto o Internet Explorer, onde a autenticação por URLs não é suportada (a chamada simplesmente não será executada).

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

Arnebert
fonte
acho que em termos de segurança é uma escolha sensata para não permitir que este
George Birbilis
O link está quebrado (404).
Peter Mortensen
10

Existem três maneiras de conseguir isso, como mostrado abaixo

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 
  },
});
GSB
fonte
8

De acordo com a resposta do SharkAlley, ele também funciona com o nginx.

Eu estava procurando uma solução para obter dados pelo jQuery a partir de um servidor atrás do nginx e restrito pelo Auth base. Isso funciona para mim:

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

E o código JavaScript é:

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

Artigo que acho útil:

  1. Respostas deste tópico
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
Maks
fonte