Sử dụng xác thực cơ bản với jQuery và Ajax


419

Tôi đang cố gắng tạo một xác thực cơ bản thông qua trình duyệt, nhưng tôi không thể thực sự đến đó.

Nếu tập lệnh này không có ở đây, xác thực trình duyệt sẽ đảm nhận, nhưng tôi muốn nói với trình duyệt rằng người dùng sắp thực hiện xác thực.

Địa chỉ nên là một cái gì đó như:

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

Tôi có một hình thức:

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

Và một kịch bả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!');
    }
});

6
Vì vậy, bạn không muốn trình duyệt xử lý xác thực BASIC? Tại sao không chỉ sử dụng xác thực dựa trên mẫu?
no.good.at.coding

@ no.good.at.coding Nếu bạn cần tích hợp với API của bên thứ ba đằng sau xác thực (đó là điều tôi đang cố gắng thực hiện - developer.zendesk.com/rest_api/docs/core/ .)
Brian Hannay

Câu trả lời:


467

Sử dụng hàm beforeSendgọi lại của jQuery để thêm tiêu đề HTTP với thông tin xác thực:

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

6
Tôi đang sử dụng ví dụ mà bạn đã đưa ra nhưng nó không hoạt động `$ .ajax ({url:" server.in.local / index.php ", beforeSend: function (xhr) {xhr.setRequestHeader (Ủy quyền ủy quyền Ngay lập tức + encodeBase64 (tên người dùng: mật khẩu));}, thành công: function (val) {// alert (val); alert ("Cảm ơn bình luận của bạn!");}}); `
Patrioticcow

69
beforeSend: function(xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password)); };làm việc cho tôi
Rico Suter

12
Vấn đề ... Nếu thông tin đăng nhập tôi vượt qua thất bại, trong Chrome, người dùng sẽ được hiển thị một hộp thoại để nhập lại tên người dùng / pwd. Làm cách nào tôi có thể ngăn hộp thoại thứ 2 này xuất hiện nếu thông tin đăng nhập thất bại?
David

2
Điều này sẽ không để lại tên người dùng và mật khẩu cho mọi người xem? Ngay cả khi nó ở cơ sở64, họ chỉ có thể giải mã nó. Tương tự với câu trả lời dưới đây.
cbron

6
@calebB Xác thực cơ bản nói chung chỉ để lại tên người dùng và mật khẩu mở cho mọi người xem. Đây không chỉ là một vấn đề với phương pháp được mô tả ở đây. Nếu xác thực cơ bản, hoặc thực sự bất kỳ xác thực nào đang được sử dụng thì SSL cũng nên được sử dụng.
Jason Jackson

354

Làm thế nào mọi thứ thay đổi trong một năm. Ngoài thuộc tính tiêu đề thay thế xhr.setRequestHeader, jQuery hiện tại (1.7.2+) bao gồm thuộc tính tên người dùng và mật khẩu với $.ajaxcuộc gọi.

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

EDIT từ các bình luận và các câu trả lời khác: Để rõ ràng - để gửi xác thực mà không có 401 Unauthorizedphản hồi, thay vì setRequestHeader(trước -1.7), hãy sử dụng '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
Có nên usernamevà không user? Ngoài ra, nó không hoàn toàn giống nhau: từ các tài liệu trực tuyến và trải nghiệm của tôi, có vẻ như nó không được ưu tiên như một số API yêu cầu. Nói cách khác, nó chỉ gửi Authorizationtiêu đề khi mã 401 được trả về.
Stefano Fratini

3
@StefanoFratini - bạn đúng cả hai cách tính. Đã sửa lỗi trường tên người dùng và thật tốt khi biết về xác thực ưu tiên và chỉ phản hồi khi thử thách. Đặt tiêu đề rõ ràng như trong các câu trả lời khác sẽ cho phép sử dụng biến thể 'thụ động' này của auth cơ bản.
jmanning2k

Đối với tôi, tùy chọn trên không hoạt động, điều này hoạt động như một cơ duyên .. cảm ơn
Anoop Isaac

Xem bình luận ở trên, vui lòng sửa câu trả lời này để cho biết {"Ủy quyền": "Cơ bản" + btoa ("người dùng: vượt qua")} làm tiêu đề chính xác
Jay

2
Đây là câu trả lời mà tôi đã tìm kiếm! Điểm mấu chốt trong câu trả lời này đối với tôi là cách 'tiêu đề' được sử dụng để gửi xác thực. Câu hỏi của tôi ở đây được trả lời bởi điều này. stackoverflow.com/questions/28404452/
Steven Anderson

63

Sử dụng cuộc gọi lại trước khi gửi để thêm tiêu đề HTTP với thông tin xác thực như sau:

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
bạn nên lưu ý rằng "btoa" được sử dụng ở đây để mã hóa Base64 không được hỗ trợ trong các phiên bản IE ít hơn 10 và trong một số nền tảng di động
TẬP

1
cũng có, theo này developer.mozilla.org/en-US/docs/DOM/window.btoa bạn nên sử dụng btoa (unescape (encodeURIComponent (str)))
SET

@SET, tôi đoán nó cần phải là btoa (encodeURIComponent (esc (str)))
Saurabh Kumar

Tôi muốn nhận được phản hồi vì vậy đã loại bỏ async sai và thêm tham số kết quả vào chức năng thành công. Tôi cũng đã có tiêu đề Ủy quyền được tạo trước để chỉ sử dụng thay thế.
radtek

1
@SET cần lưu ý rằng Base64 không mã hóa, đó là mã hóa. Nếu là mã hóa, sẽ không đơn giản để giải mã nó bằng một cuộc gọi chức năng duy nhất
Chris

40

Hoặc, chỉ cần sử dụng thuộc tính tiêu đề được giới thiệu trong 1.5:

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

Tham khảo: API Ajax jQuery


Bạn vui lòng cho tôi biết, làm thế nào để làm điều đó cho mỗi người dùng? Tôi có nghĩa là nhận mã thông báo api cho mỗi người dùng từ cơ sở dữ liệu và gửi nó với tiêu đề ajax.
Haniye Shadman

32

Các ví dụ trên có một chút khó hiểu và đây có lẽ là cách tốt nhất:

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

Tôi lấy những điều trên từ sự kết hợp giữa câu trả lời của Rico và Yossi.

Các btoa chức năng Base64 mã hóa một chuỗi.


5
Đây là một ý tưởng tồi, bởi vì bạn sẽ gửi thông tin đăng nhập với tất cả các yêu cầu AJAX, bất kể URL. Ngoài ra, tài liệu cho $.ajaxSetup()biết "Đặt giá trị mặc định cho các yêu cầu Ajax trong tương lai. Không nên sử dụng nó. "
Zero3

27

Như những người khác đã đề xuất, bạn có thể đặt tên người dùng và mật khẩu trực tiếp trong cuộc gọi Ajax:

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

HOẶC sử dụng thuộc tính tiêu đề nếu bạn không muốn lưu thông tin đăng nhập của mình dưới dạng văn bản thuần túy:

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

Dù bạn gửi nó theo cách nào thì máy chủ cũng phải rất lịch sự. Đối với Apache, tệp .htaccess của bạn sẽ trông giống như thế này:

<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

Giải trình:

Đối với một số yêu cầu tên miền chéo, trình duyệt sẽ gửi yêu cầu TÙY CHỌN trước đó thiếu các tiêu đề xác thực của bạn. Gói các chỉ thị xác thực của bạn bên trong thẻ LimitExcept để phản hồi đúng với đèn chiếu .

Sau đó gửi một vài tiêu đề để thông báo cho trình duyệt rằng nó được phép xác thực và Access-Control-Cho phép-Origin để cấp quyền cho yêu cầu chéo trang.

Trong một số trường hợp, ký tự đại diện * không hoạt động như một giá trị cho Access-Control-Allow-Origin: Bạn cần trả về tên miền chính xác của callee. Sử dụng SetEnv If để nắm bắt giá trị này.


5
Cảm ơn thông tin mà các trình duyệt gửi yêu cầu preflight CORS mà không có tiêu đề auth! Chi tiết như thế này có thể gây ra hàng giờ gỡ lỗi!
jbandi

23

Sử dụng hàm jQuery ajaxSetup , có thể thiết lập các giá trị mặc định cho tất cả các yêu cầu ajax.

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

11

JSONP không hoạt động với xác thực cơ bản nên jQuery trước khi gọi lại sẽ không hoạt động với JSONP / Script.

Tôi đã xoay sở để khắc phục giới hạn này bằng cách thêm người dùng và mật khẩu vào yêu cầu (ví dụ: user: pw@domain.tld). Điều này hoạt động với khá nhiều trình duyệt ngoại trừ Internet Explorer , nơi xác thực thông qua URL không được hỗ trợ (cuộc gọi sẽ không được thực hiện).

Xem http://support.microsoft.com/kb/834361 .


đoán rằng an ninh khôn ngoan đó là một lựa chọn lành mạnh để không cho phép điều này
George Birbilis

Liên kết bị hỏng (404).
Peter Mortensen

10

Có 3 cách để đạt được điều này như dưới đây

Cách 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 
  },
});

Cách 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 
  },
});

Cách 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

Theo câu trả lời của SharkAlley, nó cũng hoạt động với nginx.

Tôi đã tìm kiếm một giải pháp để lấy dữ liệu bằng jQuery từ một máy chủ đằng sau nginx và bị hạn chế bởi Base Auth. Điều này làm việc cho tôi:

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

Và mã JavaScript là:

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

Bài viết mà tôi thấy hữu ích:

  1. Câu trả lời của chủ đề này
  2. http://enable-cors.org/server_nginx.html
  3. http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.