Gunakan otentikasi dasar dengan jQuery dan Ajax

419

Saya mencoba membuat otentikasi dasar melalui browser, tetapi saya tidak dapat benar-benar mencapainya.

Jika skrip ini tidak ada di sini, otentikasi browser akan mengambil alih, tetapi saya ingin memberi tahu browser bahwa pengguna akan membuat otentikasi.

Alamatnya harus seperti:

http://username:[email protected]/

Saya punya formulir:

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

Dan sebuah skrip:

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
sumber
6
Jadi Anda tidak ingin browser menangani otentikasi BASIC? Mengapa tidak menggunakan otentikasi berbasis formulir?
no.good.at.coding
@ no.good.at.coding Jika Anda perlu berintegrasi dengan API pihak ketiga di balik otentikasi (yang sedang saya coba lakukan - developer.zendesk.com/rest_api/docs/core/… )
Brian Hannay

Jawaban:

467

Gunakan beforeSendpanggilan balik jQuery untuk menambahkan header HTTP dengan informasi otentikasi:

beforeSend: function (xhr) {
    xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},
Ggarber
sumber
6
saya menggunakan contoh yang Anda berikan tetapi tidak berhasil `$ .ajax ({url:" server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader (" Otorisasi "," Basic ”+ EncodeBase64 (“ username: password ”));}, succes: function (val) {// alert (val); lansiran (" Terima kasih atas komentar Anda! ");}}); `
Patrioticcow
69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };bekerja untuk saya
Rico Suter
12
Masalah ... Jika kredensial yang saya berikan gagal, di Chrome pengguna kemudian disajikan dengan dialog untuk memasukkan nama pengguna / sandi lagi. Bagaimana saya bisa mencegah dialog kedua ini muncul jika kredensial gagal?
David
2
Tidakkah ini membiarkan nama pengguna dan kata sandi di tempat terbuka untuk dilihat orang lain? Bahkan jika itu di base64 mereka hanya bisa mendekode itu. Sama dengan jawaban di bawah ini.
cbron
6
@calebB Otentikasi dasar secara umum hanya membiarkan nama pengguna dan kata sandi terbuka bagi siapa saja untuk melihatnya. Ini bukan hanya masalah dengan metode yang dijelaskan di sini. Jika otentikasi dasar, atau benar - benar otentikasi apa pun yang digunakan maka SSL juga harus digunakan.
Jason Jackson
354

Bagaimana hal berubah dalam setahun. Selain atribut tajuk sebagai pengganti xhr.setRequestHeader, jQuery saat ini (1.7.2+) menyertakan atribut nama pengguna dan kata sandi dengan $.ajaxpanggilan tersebut.

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

Sunting dari komentar dan jawaban lain: Agar lebih jelas - untuk mengirim otentikasi tanpa 401 Unauthorizedtanggapan terlebih dahulu , alih-alih setRequestHeader(pra -1.7) gunakan '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
sumber
15
Bukankah seharusnya begitu usernamedan tidak user? Juga tidak persis sama: dari dokumen daring dan pengalaman saya sepertinya itu tidak preemptive karena diperlukan beberapa API. Dengan kata lain ia mengirim Authorizationheader hanya ketika kode 401 dikembalikan.
Stefano Fratini
3
@StefanoFratini - Anda benar dalam kedua hal. Memperbaiki bidang nama pengguna, dan ada baiknya mengetahui tentang autentikasi preemptive vs merespons hanya pada tantangan. Mengatur tajuk secara eksplisit seperti pada jawaban lain akan memungkinkan penggunaan varian 'pasif' auth dasar ini.
jmanning2k
bagi saya opsi di atas tidak bekerja, ini bekerja seperti pesona .. terima kasih
Anoop Isaac
Lihat komentar di atas, perbaiki jawaban ini untuk menunjukkan {"Otorisasi": "Dasar" + btoa ("pengguna: pass")} sebagai header yang benar
Jay
2
Inilah jawaban yang telah saya cari! Bit kunci dalam jawaban ini untuk saya adalah bagaimana 'tajuk' digunakan untuk mengirim otentikasi terlebih dahulu. Pertanyaan saya di sini dijawab dengan ini. stackoverflow.com/questions/28404452/…
Steven Anderson
63

Gunakan panggilan balik beforeSend untuk menambahkan header HTTP dengan informasi otentikasi seperti:

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
sumber
4
Anda harus memperhatikan bahwa "btoa" yang digunakan di sini untuk enkripsi Base64 tidak didukung di versi IE kurang dari 10 dan di beberapa platform seluler
SET
1
juga, menurut pengembang ini.mozilla.org/en-US/docs/DOM/window.btoa Anda harus menggunakan btoa (unescape (encodeURIComponent (str)))
SET
@SET, saya kira itu harus btoa (encodeURIComponent (escape (str)))
Saurabh Kumar
Saya ingin mendapatkan respons sehingga menyingkirkan async false, dan menambahkan parameter hasil ke fungsi sukses. Saya juga memiliki header Otorisasi pra-dihasilkan jadi hanya menggunakannya sebagai gantinya.
radtek
1
@ SET harus dicatat bahwa Base64 bukan enkripsi, itu penyandian. Jika itu enkripsi, itu tidak akan sangat mudah untuk memecahkan kode itu dengan satu panggilan fungsi
Chris
40

Atau, cukup gunakan properti header yang diperkenalkan di 1.5:

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

Referensi: API jQuery Ajax

AsemRadhwi
sumber
Bisakah Anda memberi tahu saya, bagaimana cara melakukannya untuk setiap pengguna? Maksud saya mendapatkan token api untuk setiap pengguna dari basis data dan mengirimkannya dengan header ajax.
Haniye Shadman
32

Contoh di atas agak membingungkan, dan ini mungkin cara terbaik:

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

Saya mengambil di atas dari kombinasi Rico dan jawaban Yossi.

The btoa fungsi Base64 encode string.

Paul Odeon
sumber
5
Ini adalah ide yang buruk, karena Anda akan mengirim informasi masuk dengan semua permintaan AJAX, terlepas dari URL. Juga, dokumentasi untuk $.ajaxSetup()mengatakan "Tetapkan nilai default untuk permintaan Ajax di masa depan. Penggunaannya tidak dianjurkan. "
Zero3
27

Seperti yang disarankan orang lain, Anda dapat mengatur nama pengguna dan kata sandi secara langsung di panggilan Ajax:

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

ATAU gunakan properti header jika Anda lebih suka tidak menyimpan kredensial Anda dalam teks biasa:

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

Apapun cara Anda mengirimnya, server harus sangat sopan. Untuk Apache, file .htaccess Anda akan terlihat seperti ini:

<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

Penjelasan:

Untuk beberapa permintaan lintas domain, browser mengirim permintaan PILIHAN prelight yang tidak ada tajuk otentikasi Anda. Bungkus arahan otentikasi Anda di dalam tag LimitExcept untuk merespons dengan benar pada preflight.

Kemudian kirim beberapa tajuk untuk memberi tahu peramban bahwa browser diizinkan untuk diautentikasi, dan Access-Control-Allow-Origin untuk memberikan izin untuk permintaan lintas situs.

Dalam beberapa kasus, * wildcard tidak berfungsi sebagai nilai untuk Access-Control-Allow-Origin: Anda harus mengembalikan domain persis dari callee. Gunakan SetEnvIf untuk mengambil nilai ini.

SharkAlley
sumber
5
Terima kasih atas info bahwa browser mengirim permintaan preflight CORS tanpa header auth! Detail seperti ini dapat menyebabkan berjam-jam debug!
jbandi
23

Gunakan fungsi ajaxSetup jQuery , yang dapat mengatur nilai default untuk semua permintaan ajax.

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

JSONP tidak bekerja dengan autentikasi dasar sehingga jQuery beforeKirim panggilan balik tidak akan berfungsi dengan JSONP / Script.

Saya berhasil mengatasi batasan ini dengan menambahkan pengguna dan kata sandi ke permintaan (misalnya pengguna: [email protected]). Ini berfungsi dengan hampir semua browser kecuali Internet Explorer mana otentikasi melalui URL tidak didukung (panggilan tidak akan dieksekusi).

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

Arnebert
sumber
coba
Tautan rusak (404).
Peter Mortensen
10

Ada 3 cara untuk mencapai ini seperti yang ditunjukkan di bawah ini

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

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

Metode 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
sumber
8

Menurut jawaban SharkAlley itu bekerja dengan nginx juga.

Saya sedang mencari solusi untuk mendapatkan data dengan jQuery dari server di belakang nginx dan dibatasi oleh Pangkalan Auth. Ini bekerja untuk saya:

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

Dan kode JavaScript adalah:

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

Artikel yang menurut saya bermanfaat:

  1. Jawaban topik ini
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
Maks
sumber