ใช้การรับรองความถูกต้องเบื้องต้นกับ jQuery และ Ajax


419

ฉันกำลังพยายามสร้างการรับรองความถูกต้องเบื้องต้นผ่านเบราว์เซอร์ แต่ฉันไปไม่ได้จริงๆ

หากสคริปต์นี้ไม่ได้อยู่ที่นี่การตรวจสอบความถูกต้องของเบราว์เซอร์จะเข้ามาแทนที่ แต่ฉันต้องการบอกเบราว์เซอร์ว่าผู้ใช้กำลังทำการตรวจสอบสิทธิ์

ที่อยู่ควรมีลักษณะดังนี้:

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

ฉันมีแบบฟอร์ม:

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

และสคริปต์:

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
ดังนั้นคุณไม่ต้องการให้เบราว์เซอร์จัดการการรับรองความถูกต้องเบื้องต้นใช่หรือไม่ ทำไมไม่ใช้การรับรองความถูกต้องตามแบบฟอร์ม?
no.good.at.coding

@ no.good.at.coding หากคุณต้องการรวมกับ API ของบุคคลที่สามที่อยู่เบื้องหลังการรับรองความถูกต้อง (ซึ่งเป็นสิ่งที่ฉันพยายามจะทำ - developer.zendesk.com/rest_api/docs/core/ ...... )
Brian Hannay

คำตอบ:


467

ใช้การbeforeSendเรียกกลับของ jQuery เพื่อเพิ่มส่วนหัว HTTP ด้วยข้อมูลการตรวจสอบความถูกต้อง:

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

6
ฉันใช้ตัวอย่างที่คุณให้ แต่มันไม่ทำงาน `$ .ajax ({url:" server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader (“ การอนุญาต”,“ พื้นฐาน ” + encodeBase64 (“ ชื่อผู้ใช้: รหัสผ่าน”));}, สำเร็จ: ฟังก์ชั่น (val) {// alert (val); alert ("ขอบคุณสำหรับความคิดเห็นของคุณ!");}}); `
Patrioticcow

69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };ทำงานให้ฉัน
Rico Suter

12
ปัญหา ... หากข้อมูลประจำตัวที่ฉันส่งผ่านล้มเหลวใน Chrome ผู้ใช้จะได้รับการนำเสนอพร้อมช่องโต้ตอบเพื่อป้อนชื่อผู้ใช้ / pwd อีกครั้ง ฉันจะป้องกันไม่ให้กล่องโต้ตอบที่ 2 นี้ปรากฏขึ้นได้อย่างไรหากข้อมูลรับรองล้มเหลว
David

2
การดำเนินการนี้จะไม่ปล่อยให้ชื่อผู้ใช้และรหัสผ่านเปิดให้ใครเห็นหรือไม่ แม้ว่ามันจะอยู่ใน base64 พวกเขาก็สามารถถอดรหัสได้ เช่นเดียวกันกับคำตอบด้านล่าง
cbron

6
@calebB การรับรองความถูกต้องพื้นฐานโดยทั่วไปเพียงแค่ปล่อยให้ชื่อผู้ใช้และรหัสผ่านในการเปิดให้ทุกคนเห็น นี่ไม่ใช่เพียงปัญหากับวิธีการที่อธิบายไว้ที่นี่ หากการรับรองความถูกต้องเบื้องต้นหรือการตรวจสอบความถูกต้องจริงใด ๆ ที่มีการใช้ SSL ก็ควรได้รับการว่าจ้าง
Jason Jackson

354

สิ่งต่าง ๆ เปลี่ยนแปลงในหนึ่งปี นอกเหนือจากแอตทริบิวต์ส่วนหัวแทนที่xhr.setRequestHeaderjQuery ปัจจุบัน (1.7.2+) รวมถึงชื่อผู้ใช้และแอตทริบิวต์รหัสผ่านด้วยการ$.ajaxโทร

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

แก้ไขจากความคิดเห็นและคำตอบอื่น ๆ : เพื่อความชัดเจน - เพื่อส่งการรับรองความถูกต้องโดยไม่ต้อง401 Unauthorizedตอบสนองแทนการใช้setRequestHeader(ก่อน -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!'); 
  }
});

15
ไม่ควรหรือusernameไม่user? นอกจากนี้ยังไม่เหมือนกัน: จาก docos ออนไลน์และประสบการณ์ของฉันดูเหมือนว่าจะไม่ได้รับการยกเว้นตาม API บางตัวที่ต้องการ กล่าวอีกนัยหนึ่งมันจะส่งAuthorizationส่วนหัวเฉพาะเมื่อโค้ด 401 ถูกส่งคืน
Stefano Fratini

3
@StefanoFratini - คุณถูกต้องทั้งสองจำนวน แก้ไขฟิลด์ชื่อผู้ใช้และเป็นการดีที่จะรู้เกี่ยวกับการรับรองความถูกต้องแบบป้องกันและตอบกลับเฉพาะเมื่อมีความท้าทาย การตั้งค่าส่วนหัวอย่างชัดเจนเช่นเดียวกับคำตอบอื่น ๆ จะช่วยให้การใช้ตัวแปร 'เรื่อย ๆ ' ของการรับรองความถูกต้องพื้นฐานนี้
jmanning2k

สำหรับฉันตัวเลือกข้างต้นใช้งานไม่ได้ทำงานเช่นนี้มีเสน่ห์ .. ขอบคุณ
Anoop Isaac

ดูความคิดเห็นด้านบนโปรดแก้ไขคำตอบนี้เพื่อระบุ {"การอนุญาต": "พื้นฐาน" + btoa ("ผู้ใช้: ผ่าน")} เป็นส่วนหัวที่ถูกต้อง
Jay

2
นี่คือคำตอบที่ฉันได้ดู! คีย์บิตในคำตอบนี้สำหรับฉันคือการใช้ 'ส่วนหัว' เพื่อส่งการรับรองความถูกต้องล่วงหน้า คำถามของฉันที่นี่ตอบโดยนี้ stackoverflow.com/questions/28404452/…
Steven Anderson

63

ใช้beforeSend callbackเพื่อเพิ่มส่วนหัว HTTP ด้วยข้อมูลการตรวจสอบสิทธิ์เช่น:

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
คุณควรสังเกตว่า "btoa" ที่ใช้ที่นี่สำหรับการเข้ารหัส Base64 ไม่รองรับใน IE เวอร์ชันที่น้อยกว่า 10 และในบางแพลตฟอร์มมือถือ
SET

1
นอกจากนี้ตามที่ผู้พัฒนาเว็บนี้บอกไว้ว่าคุณควรใช้ btoa (unescape (encodeURIComponent (str))
SET

@ ชุดฉันเดาว่ามันต้องเป็น btoa (encodeURIComponent (หลบหนี (str)))
Saurabh Kumar

ฉันต้องการได้รับการตอบสนองเพื่อกำจัด async false และเพิ่มพารามิเตอร์ผลลัพธ์ลงในฟังก์ชันความสำเร็จ ฉันยังมีส่วนหัวการให้สิทธิ์ที่สร้างไว้ล่วงหน้าดังนั้นควรใช้แทน
radtek

1
@SET ควรสังเกตว่า Base64 ไม่ใช่การเข้ารหัส แต่เป็นการเข้ารหัส หากเป็นการเข้ารหัสมันจะไม่ง่ายอย่างที่จะถอดรหัสด้วยการเรียกใช้ฟังก์ชันเดียว
Chris

40

หรือเพียงใช้คุณสมบัติส่วนหัวที่แนะนำใน 1.5:

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

การอ้างอิง: jQuery Ajax API


คุณช่วยกรุณาบอกฉันว่าจะทำอย่างไรสำหรับผู้ใช้แต่ละคน? ฉันหมายถึงรับ api โทเค็นสำหรับผู้ใช้แต่ละคนจากฐานข้อมูลและส่งด้วยส่วนหัว Ajax
Haniye Shadman

32

ตัวอย่างข้างต้นค่อนข้างสับสนและอาจเป็นวิธีที่ดีที่สุด:

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

ฉันใช้คำพูดข้างต้นจากคำตอบของ Rico และ Yossi

btoaฟังก์ชั่นBase64เข้ารหัสสตริง


5
นี่เป็นความคิดที่ไม่ดีเพราะคุณจะส่งข้อมูลเข้าสู่ระบบด้วยคำขอ AJAX ทั้งหมดไม่ว่า URL จะเป็นเช่นไร นอกจากนี้ยังมีเอกสารสำหรับ$.ajaxSetup()พูดว่า "ตั้งค่าเริ่มต้นสำหรับคำขอ Ajax ในอนาคตไม่แนะนำให้ใช้ "
Zero3 3

27

ตามที่คนอื่นแนะนำคุณสามารถตั้งชื่อผู้ใช้และรหัสผ่านโดยตรงในการโทร Ajax:

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

หรือใช้คุณสมบัติส่วนหัวหากคุณไม่ต้องการเก็บข้อมูลประจำตัวของคุณเป็นข้อความธรรมดา:

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

ไม่ว่าคุณจะส่งทางไหนเซิร์ฟเวอร์จะต้องสุภาพมาก สำหรับ Apache ไฟล์. htaccess ของคุณควรมีลักษณะดังนี้:

<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

คำอธิบาย:

สำหรับคำขอข้ามโดเมนบางรายการเบราว์เซอร์จะส่งคำขอOPTIONS preflight ที่ไม่มีส่วนหัวการตรวจสอบสิทธิ์ของคุณ ตัดคำสั่งการตรวจสอบสิทธิ์ของคุณภายในแท็กLimitExceptเพื่อตอบสนองอย่างเหมาะสมกับ preflight

จากนั้นส่งส่วนหัวเล็กน้อยเพื่อบอกเบราว์เซอร์ว่าได้รับอนุญาตให้ตรวจสอบความถูกต้องและ Access-Control-Allow-Originเพื่อให้สิทธิ์สำหรับคำขอข้ามไซต์

ในบางกรณี* wildcard ไม่ทำงานเป็นค่าสำหรับ Access-Control-Allow-Origin: คุณต้องส่งคืนโดเมนที่ถูกต้องของ callee ใช้ SetEnvIf เพื่อจับภาพค่านี้


5
ขอบคุณสำหรับข้อมูลที่เบราว์เซอร์ส่งคำขอ preflight CORS โดยไม่ต้องมีส่วนหัวรับรองความถูกต้อง! รายละเอียดเช่นนี้อาจทำให้การดีบักหลายชั่วโมง!
jbandi

23

ใช้ฟังก์ชันjQuery ajaxSetupที่สามารถตั้งค่าเริ่มต้นสำหรับการร้องขอ ajax ทั้งหมด

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

11

JSONPไม่ทำงานกับการพิสูจน์ตัวตนพื้นฐานดังนั้น jQuery ก่อนการโทรกลับจะไม่ทำงานกับ JSONP / สคริปต์

ฉันจัดการเพื่อแก้ไขข้อ จำกัด นี้โดยการเพิ่มผู้ใช้และรหัสผ่านลงในคำขอ (เช่นผู้ใช้: pw@domain.tld) ใช้งานได้กับเบราว์เซอร์ใด ๆยกเว้น Internet Explorerที่ไม่รองรับการตรวจสอบสิทธิ์ผ่าน URL (การโทรจะไม่ถูกเรียกใช้งาน)

ดูhttp://support.microsoft.com/kb/834489


เดาว่าการรักษาความปลอดภัยนั้นเป็นทางเลือกที่มีเหตุผลที่จะไม่อนุญาตสิ่งนี้
George Birbilis

ลิงก์ใช้งานไม่ได้ (404)
Peter Mortensen

10

มี 3 วิธีในการบรรลุเป้าหมายดังที่แสดงด้านล่าง

วิธีที่ 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 
  },
});

วิธีที่ 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 
  },
});

วิธีที่ 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

ตาม SharkAlley ตอบมันทำงานกับ nginx ด้วย

ฉันค้นหาวิธีแก้ปัญหาเพื่อรับข้อมูลโดย jQuery จากเซิร์ฟเวอร์ที่อยู่หลัง nginx และถูก จำกัด โดย Base Auth สิ่งนี้ใช้ได้กับฉัน:

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

และรหัส JavaScript คือ:

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

บทความที่ฉันพบว่ามีประโยชน์:

  1. คำตอบของหัวข้อนี้
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.