Tại sao phương thức .ajax () của jquery không gửi cookie phiên của tôi?


338

Sau khi đăng nhập qua $.ajax()một trang web, tôi đang cố gắng gửi $.ajax()yêu cầu thứ hai đến trang web đó - nhưng khi tôi kiểm tra các tiêu đề được gửi bằng FireBug, không có cookie phiên nào được đưa vào yêu cầu.

Tôi đang làm gì sai?


2
Cookie của ajax có thể xuất hiện sau cookie web và FireBug có thể bắt cookie trang đầu tiên.
Chris

1
Tôi không hiểu ý bạn là gì nhưng tôi có thể nói nếu tôi dán url yêu cầu vào thanh địa chỉ trình duyệt và kiểm tra lại Fireorms, tôi có thể thấy cookie trong các tiêu đề được gửi đến máy chủ. Giải pháp nào?
user345625

Vì vậy, tôi nghĩ rằng ajax cũng sẽ xử lý theo cách tương tự trình duyệt
user345625

Mã bạn đang sử dụng là gì?
Dean Harding

trình duyệt vẫn sẽ tạo cookie do máy chủ đặt trong yêu cầu ajax, jquery hoặc cách khác. Bạn đã kiểm tra phản hồi cho yêu cầu ajax và đảm bảo cookie quay lại từ máy chủ sẽ được đặt chưa? Có thể có một vấn đề với mã máy chủ sao cho nó thậm chí không đặt cookie, v.v.
David

Câu trả lời:


218

Cuộc gọi AJAX chỉ gửi Cookies nếu url bạn đang gọi nằm trên cùng một tên miền với tập lệnh gọi của bạn.

Đây có thể là một vấn đề tên miền chéo.

Có thể bạn đã cố gọi một url từ www.domain-a.comkhi tập lệnh gọi của bạn được bật www.domain-b.com(Nói cách khác: Bạn đã thực hiện Cuộc gọi tên miền chéo trong trường hợp trình duyệt sẽ không gửi bất kỳ cookie nào để bảo vệ quyền riêng tư của bạn).

Trong trường hợp này, các tùy chọn của bạn là:

  • Viết một proxy nhỏ nằm trên domain-b và chuyển tiếp yêu cầu của bạn đến domain-a. Trình duyệt của bạn sẽ cho phép bạn gọi proxy vì nó trên cùng một máy chủ với tập lệnh gọi.
    Proxy này sau đó có thể được cấu hình để bạn chấp nhận tên cookie và tham số giá trị mà nó có thể gửi đến miền-a. Nhưng để làm việc này, bạn cần biết tên của cookie và giá trị máy chủ của bạn trên miền - muốn xác thực.
  • Nếu bạn đang tìm nạp các đối tượng JSON, hãy thử sử dụng một yêu cầu JSONP thay thế. jQuery hỗ trợ những thứ này. Nhưng bạn cần thay đổi dịch vụ của mình trên miền-a để nó trả về phản hồi JSONP hợp lệ.

Vui mừng nếu điều đó giúp một chút.


19
Cũng đáng lưu ý rằng cookie có thể được đặt thành một đường dẫn cụ thể vì vậy nếu cookie của bạn được đặt path=/somethingvà bạn đang yêu cầu trang /anotherthì cookie sẽ không được gửi. Khi bạn yêu cầu trang /something, cookie sẽ được gửi như mong đợi. Vì vậy, kiểm tra mã đặt cookie là tốt.
styfle

2
một yêu cầu jsonp gửi coockies?
albanx

1
@albanx Có, nếu các yêu cầu tôi đề cập được đặt ra. Đó chỉ là một yêu cầu bình thường như mọi yêu cầu khác và như vậy sẽ gửi cookie.
cúm

1
@albanx câu hỏi liên quan khác này bao gồm một ví dụ về cách thực hiện yêu cầu JSONP đó với cookie tùy chỉnh
AntonioHerraizS

4
Theo JSONP trên Wikipedia> phương pháp này đã bị từ bỏ để ủng hộ CORS
Peter Dotchev

386

Tôi đang hoạt động trong kịch bản tên miền chéo. Trong quá trình đăng nhập, máy chủ từ xa đang trả về tiêu đề Set-Cookie cùng với Access-Control-Allow-Credentialsđược đặt thành true.

Cuộc gọi ajax tiếp theo đến máy chủ từ xa sẽ sử dụng cookie này.

CORS Access-Control-Allow-Credentialscó mặt để cho phép đăng nhập tên miền chéo. Kiểm tra https://developer.mozilla.org/En/HTTP_access_control để biết ví dụ.

Đối với tôi, nó có vẻ như là một lỗi trong JQuery (hoặc ít nhất là tính năng tương tự trong phiên bản tiếp theo).

CẬP NHẬT:

  1. Cookies không được đặt tự động từ phản hồi AJAX (trích dẫn: http://aleembawany.com/2006/11/14/anatomy-of-a-well-design-ajax-login-experience/ )

    Tại sao?

  2. Bạn không thể nhận giá trị của cookie từ phản hồi để đặt thủ công ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader )

    Tôi bối rối..

    Cần tồn tại một cách để yêu cầu jquery.ajax()thiết lập XMLHttpRequest.withCredentials = "true"tham số.

TRẢ LỜI: Bạn nên sử dụng xhrFieldsparam của http://api.jquery.com/jQuery.ajax/

Ví dụ trong tài liệu là:

$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
      withCredentials: true
   }
});

Điều quan trọng là máy chủ trả lời chính xác cho yêu cầu này. Sao chép ở đây những bình luận tuyệt vời từ @ Frédéric và @Pebbl:

Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: *

Vì vậy, khi yêu cầu là:

Origin: http://foo.example
Cookie: pageAccess=2

Máy chủ sẽ phản hồi với:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true

[payload]

Nếu không, tải trọng sẽ không được trả lại cho tập lệnh. Xem: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials


8
Tuyệt quá ! Tôi thêm để sử dụng + đặt tiêu đề Access-Control-Cho phép-Thông tin xác thực này thành đúng ở phía máy chủ
Frédéric

và tôi đặt các Thông tin đó ở đâu?, tại Tiêu đề Tự động hóa?, tại cơ quan yêu cầu?
Francisco Corrales Morales

3
Cảm ơn câu trả lời :) chỉ là một bổ sung nhanh chóng, có thể đáng để đề cập đến Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: * developer.mozilla.org/en-US/docs/Web/HTTP/
mẹo

Không ai trong số này làm việc cho tôi không may. Nếu tôi chạy cùng một yêu cầu từ AngularJS thì nó hoạt động, nhưng từ jQuery, ngay cả với những gợi ý này, phiên Cookie không được thông qua. (jQuery v2.1.1)
địa lý

(OO) Bạn đã cứu tôi khỏi nhiều giờ đau đớn. Thật là một câu trả lời hoàn hảo! Cảm ơn! Tôi cần thêm những trong .htaccess gốc nào của trang web của tôi: <IfModule mod_headers.c> Tiêu đề thiết lập Access-Control-Allow-Origin " localhost " Header thiết lập Access-Control-Allow-Credentials "true" </ IfModule>
Vinay Vissh

48

Sử dụng

xhrFields: { withCredentials:true }

như một phần của lệnh gọi ajax jQuery của tôi chỉ là một phần của giải pháp. Tôi cũng cần phải trả lại các tiêu đề trong phản hồi TÙY CHỌN từ tài nguyên của mình:

Access-Control-Allow-Origin : http://www.wombling.com
Access-Control-Allow-Credentials : true

Điều quan trọng là chỉ có một "nguồn gốc" được phép nằm trong tiêu đề phản hồi của lệnh gọi TÙY CHỌN chứ không phải "*". Tôi đã đạt được điều này bằng cách đọc nguồn gốc từ yêu cầu và đưa nó trở lại phản hồi - có thể tránh được lý do ban đầu cho sự hạn chế, nhưng trong trường hợp sử dụng của tôi, bảo mật không phải là tối quan trọng.

Tôi nghĩ rằng đáng để đề cập rõ ràng yêu cầu chỉ có một nguồn gốc, vì tiêu chuẩn W3C không cho phép một danh sách được phân tách không gian - nhưng Chrome thì không! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB bit "trong thực tế".


41

Đặt cái này trong hàm init của bạn:

$.ajaxSetup({
  xhrFields: {
    withCredentials: true
  }
});

Nó sẽ làm việc.


1
Bạn đã cứu ngày của tôi! Ở cấp độ phương thức, withCredentials không hoạt động với tôi. Nhưng thế giới như thế này cuối cùng nó hoạt động! Cảm ơn.
Paulius Matulionis

hãy cẩn thận với nó, bởi vì nó sẽ gửi cookie cho tất cả các yêu cầu, ether cho các tên miền khác (không mong đợi điều này và yêu cầu không thành công bằng cách yêu cầu Access-Control-Cho phép-Thông tin xác thực)
devi

12

Đã có rất nhiều câu trả lời tốt cho câu hỏi này, nhưng tôi nghĩ có thể hữu ích để làm rõ trường hợp bạn muốn gửi cookie phiên vì tên miền cookie phù hợp, nhưng nó không được gửi vì yêu cầu AJAX là được thực hiện cho một tên miền phụ khác. Trong trường hợp này, tôi có một cookie được gán cho các * .mydomain.com miền, và tôi muốn nó được đưa vào một yêu cầu AJAX để different.mydomain.com ". Theo mặc định, các tập tin cookie không được gửi. Bạn không cần phải tắt HTTPONLY trên cookie phiên để giải quyết vấn đề này. Bạn chỉ cần thực hiện những gì đã đề nghị ( https://stackoverflow.com/a/23660618/545223 ) và làm như sau.

1) Thêm sau đây vào yêu cầu ajax của bạn.

xhrFields: { withCredentials:true }

2) Thêm phần sau vào tiêu đề phản hồi của bạn cho các tài nguyên trong tên miền phụ khác nhau.

Access-Control-Allow-Origin : http://original.mydomain.com
Access-Control-Allow-Credentials : true

7

Sau khi thử các giải pháp khác và vẫn không làm cho nó hoạt động, tôi đã tìm ra vấn đề trong trường hợp của tôi. Tôi đã thay đổi contentType từ "application / json" thành "text / plain".

$.ajax(fullUrl, {
    type: "GET",
    contentType: "text/plain",
    xhrFields: {
         withCredentials: true
    },
    crossDomain: true
});

4

Tôi đã gặp vấn đề tương tự và thực hiện một số kiểm tra kịch bản của tôi chỉ đơn giản là không nhận được cookie phiên.

Tôi đã tìm ra bằng cách xem giá trị cookie sessionid trong trình duyệt rằng khung của tôi (Django) đã vượt qua cookie sessionid với httpOnly làm mặc định. Điều này có nghĩa là các tập lệnh không có quyền truy cập vào giá trị sessionid và do đó không chuyển nó cùng với các yêu cầu. Thật là nực cười khi httpOnly sẽ là giá trị mặc định khi có rất nhiều thứ sử dụng Ajax yêu cầu hạn chế truy cập.

Để khắc phục điều này, tôi đã thay đổi cài đặt (SESSION_COOKIE_HTTPONLY = Sai) nhưng trong các trường hợp khác, đó có thể là cờ "HttpOnly" trên đường dẫn cookie


2
KHÔNG làm điều này. Nó cho phép tập lệnh phía máy khách truy cập vào cookie phiên là vectơ tấn công XSS phổ biến nhất. owasp.org/index.php/HttpOnly
Jason Elkin

1

Nếu bạn đang phát triển trên localhosthoặc một cổng trên localhost, chẳng hạn như localhost:8080, ngoài các bước được mô tả trong các câu trả lời ở trên, bạn cũng cần đảm bảo rằng bạn không chuyển một giá trị miền trong tiêu đề Set-Cookie.
Bạn không thể đặt tên miền thành localhosttrong tiêu đề Set-Cookie - không chính xác - chỉ cần bỏ qua tên miền.

Xem Cookies trên localhost với tên miền rõ ràngTại sao asp.net không tạo cookie trong localhost?


0

Chỉ cần 2 xu của tôi khi đặt vấn đề cookie PHPSESSID khi trên localhost và trong môi trường dev. Tôi thực hiện cuộc gọi AJAX đến điểm cuối API REST của mình trên đầu máy. Nói địa chỉ của nó là mysite.localhost/api/member/login/(máy chủ đạo đức trên môi trường dev của tôi).

  • Khi tôi thực hiện yêu cầu này trên Postman , mọi thứ sẽ ổn và PHPSESSID được đặt với phản hồi.

  • Khi tôi yêu cầu điểm cuối này qua AJAX từ trang được ủy quyền của Trình duyệt (ví dụ: 122.133.1.110:3000/test/api/login.phptrong dòng địa chỉ trình duyệt của tôi, hãy xem tên miền khác so với mysite.localhost) PHPSESSID không xuất hiện giữa các cookie.

  • Khi tôi thực hiện yêu cầu này trực tiếp từ trang trên cùng một tên miền (nghĩa là mysite.localhost/test/api/login.php) PHPSESSID được đặt tốt.

Vì vậy, đây là vấn đề cookie yêu cầu nguồn gốc xuất xứ chéo như được đề cập trong câu trả lời @flu ở trên


0

Thêm kịch bản và giải pháp của tôi trong trường hợp nó giúp người khác. Tôi gặp trường hợp tương tự khi sử dụng API RESTful. Máy chủ Web của tôi lưu trữ tệp HTML / Script / CSS và API hiển thị Máy chủ ứng dụng được lưu trữ trên cùng một tên miền. Tuy nhiên, con đường đã khác.

máy chủ web - mydomain / trang web /abc.html

đã sử dụng abc.js để đặt cookie có tên mycookie

máy chủ ứng dụng - mydomain / webapis / tên dịch vụ.

cuộc gọi api đã được thực hiện

Tôi đã mong đợi cookie trong mydomain / webapis / servicename và đã thử đọc nó nhưng nó không được gửi. Sau khi đọc nhận xét từ câu trả lời, tôi đã kiểm tra trong công cụ phát triển của trình duyệt rằng đường dẫn của mycookie được đặt thành "/ trang web " và do đó không có sẵn trong cuộc gọi dịch vụ tới

mydomain / webapis / servicename

Vì vậy, trong khi đặt cookie từ jquery, đây là những gì tôi đã làm -

$.cookie("mycookie","mayvalue",{**path:'/'**});

-5

Có lẽ không trả lời 100% câu hỏi, nhưng tôi tình cờ gặp chủ đề này với hy vọng giải quyết vấn đề phiên khi ajax đăng tải một tập tin tải lên từ trình quản lý tài sản của trình soạn thảo đổi mới. Cuối cùng, giải pháp rất đơn giản: họ có một trình tải lên flash. Vô hiệu hóa điều đó (cài đặt

var flashUpload = false;   

trong property.php) và đèn lại bắt đầu nhấp nháy.

Vì những vấn đề này có thể rất khó để gỡ lỗi, tôi thấy rằng việc đưa một cái gì đó như sau vào trình xử lý tải lên sẽ đưa bạn (tốt, tôi trong trường hợp này) đi đúng hướng:

$sn=session_name();
error_log("session_name: $sn ");

if(isset($_GET[$sn])) error_log("session as GET param");
if(isset($_POST[$sn])) error_log("session as POST param");
if(isset($_COOKIE[$sn])) error_log("session as Cookie");
if(isset($PHPSESSID)) error_log("session as Global");

Đi sâu vào nhật ký và tôi nhanh chóng phát hiện ra phiên bị mất, nơi không có cookie nào được gửi.


Tôi không nghĩ ví dụ trên sẽ hoạt động, vì khi không có cookie phiên, giá trị của $ sn sẽ là bao nhiêu? (một cách ngẫu nhiên, hoặc có thể là không), người dùng thay thế có thể đặt session_name từ giá trị GET, ví dụ như session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();vậy, họ sẽ có được một thứ hoạt động
Steel Brain

Đó chính xác là cách tôi tìm thấy vấn đề: không có phiên nào khi đăng bài từ trình tải lên flash này. Vì sử dụng một định danh phiên biến GET là một ý tưởng tồi và cookie không hoạt động, tôi đã ném nó ra. Ai quan tâm, flash là một điều của quá khứ.
Ellert van Koperen
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.