Mengapa metode .ajax () jquery tidak mengirim cookie sesi saya?

338

Setelah masuk melalui $.ajax()ke situs, saya mencoba mengirim $.ajax()permintaan kedua ke situs itu - tetapi ketika saya memeriksa header yang dikirim menggunakan FireBug, tidak ada cookie sesi yang dimasukkan dalam permintaan.

Apa yang saya lakukan salah?

pengguna345625
sumber
2
Cookie ajax mungkin muncul setelah cookie web dan FireBug mungkin menangkap cookie halaman pertama.
Chris
1
Saya tidak mengerti maksud Anda tetapi saya dapat mengatakan jika saya menempelkan url permintaan di bilah alamat browser dan memeriksa Firebug lagi, saya bisa melihat cookie di headres dikirim ke server. Ada solusi?
user345625
Jadi, saya pikir ajax juga akan menangani browser dengan cara yang sama
user345625
Apa kode yang Anda gunakan?
Dean Harding
browser akan tetap membuat cookie yang ditetapkan oleh server selama permintaan ajax, jquery atau lainnya. Apakah Anda memeriksa respons terhadap permintaan ajax dan memastikan cookie kembali dari server untuk ditetapkan? Mungkin ada masalah dengan kode server sehingga tidak mengatur cookie, dll.
David

Jawaban:

218

Panggilan AJAX hanya mengirim Cookie jika url yang Anda panggil berada di domain yang sama dengan skrip panggilan Anda.

Ini mungkin Masalah Lintas Domain.

Mungkin Anda mencoba menelepon url dari www.domain-a.comsaat skrip panggilan Anda aktif www.domain-b.com(Dengan kata lain: Anda membuat Panggilan Domain Silang yang mana peramban tidak akan mengirim cookie apa pun untuk melindungi privasi Anda).

Dalam hal ini opsi Anda adalah:

  • Tulis proxy kecil yang berada di domain-b dan kirimkan permintaan Anda ke domain-a. Browser Anda akan memungkinkan Anda untuk memanggil proxy karena berada di server yang sama dengan skrip panggilan.
    Proxy ini kemudian dapat dikonfigurasi oleh Anda untuk menerima nama cookie dan parameter nilai yang dapat dikirim ke domain-a. Tetapi agar ini berfungsi, Anda perlu mengetahui nama cookie dan menghargai server Anda pada domain-a yang ingin otentikasi.
  • Jika Anda mengambil objek JSON coba gunakan permintaan JSONP sebagai gantinya. jQuery mendukung ini. Tetapi Anda perlu mengubah layanan Anda di domain-a sehingga mengembalikan respons JSONP yang valid.

Senang jika itu sedikit membantu.

flu
sumber
19
Perlu juga dicatat bahwa cookie dapat diatur ke jalur tertentu sehingga jika cookie Anda diatur dengan path=/somethingdan Anda meminta halaman /anothermaka cookie tidak akan dikirim. Ketika Anda meminta halaman /something, cookie akan dikirim seperti yang diharapkan. Jadi periksa kode yang mengatur cookie juga.
styfle
2
apakah permintaan jsonp mengirim coockies?
albanx
1
@albanx Ya, jika persyaratan yang saya sebutkan diatur. Itu hanya permintaan normal seperti yang lainnya dan karena itu mengirim cookie.
Flu
1
@albanx pertanyaan terkait lainnya ini mencakup contoh bagaimana melakukan permintaan JSONP dengan cookie khusus
AntonioHerraizS
4
Menurut JSONP di Wikipedia> pendekatan ini ditinggalkan demi CORS
Peter Dotchev
388

Saya beroperasi dalam skenario lintas-domain. Selama login server jauh mengembalikan header Set-Cookie bersama dengan Access-Control-Allow-Credentialsset ke true.

Panggilan ajax berikutnya ke server jauh harus menggunakan cookie ini.

CORS Access-Control-Allow-Credentialsada untuk memungkinkan penebangan lintas domain. Periksa https://developer.mozilla.org/En/HTTP_access_control untuk contoh.

Bagi saya sepertinya ada bug di JQuery (atau paling tidak fitur-to-be di versi berikutnya).

MEMPERBARUI:

  1. Cookie tidak diatur secara otomatis dari respons AJAX (kutipan: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/ )

    Mengapa?

  2. Anda tidak bisa mendapatkan nilai cookie dari respons untuk mengaturnya secara manual ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader )

    Saya bingung..

    Seharusnya ada cara untuk meminta jquery.ajax()untuk mengatur XMLHttpRequest.withCredentials = "true"parameter.

JAWABAN: Anda harus menggunakan xhrFieldsparam dari http://api.jquery.com/jQuery.ajax/

Contoh dalam dokumentasi adalah:

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

Penting juga bahwa server menjawab dengan benar permintaan ini. Menyalin komentar hebat di sini dari @ Frédéric dan @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: *

Jadi ketika permintaannya adalah:

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

Server harus merespons dengan:

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

[payload]

Kalau tidak, payload tidak akan dikembalikan ke skrip. Lihat: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials

Kangur
sumber
8
Bagus ! Saya menambahkan untuk menggunakan + set header Access-Control-Allow-Credentials ini menjadi true di sisi server
Frédéric
dan di mana saya mengatur Kredensial itu ?, di Header Autorization?, di badan permintaan?
Francisco Corrales Morales
3
Terima kasih atas jawabannya :) hanya tambahan cepat, mungkin layak disebut 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/…
Pebbl
Sayangnya, semua ini tidak berhasil bagi saya. Jika saya menjalankan permintaan yang sama dari AngularJS berfungsi, tetapi dari jQuery, bahkan dengan saran-saran ini Cookie sesi tidak berlalu. (jQuery v2.1.1)
geoidesic
(OO) Anda menyelamatkan saya dari berbagai jam menyakitkan. Jawaban yang sempurna! Terima kasih! Saya perlu menambahkan ini di root publik .htaccess dari situs web saya: <IfModule mod_headers.c> Header set Access-Control-Allow-Origin " localhost " Header set Access-Control-Allow-Kredensial "true" </IfModule>
Vinay Vissh
48

Menggunakan

xhrFields: { withCredentials:true }

sebagai bagian dari panggilan ajax jQuery saya hanya bagian dari solusi. Saya juga perlu meminta header dikembalikan dalam tanggapan OPSI dari sumber saya:

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

Penting bahwa hanya satu "asal" yang diizinkan berada di tajuk respons panggilan OPSI dan bukan "*". Saya mencapai ini dengan membaca asal dari permintaan dan mengisinya kembali ke respons - mungkin menghindari alasan asli untuk pembatasan, tetapi dalam kasus penggunaan saya keamanan tidak penting.

Saya pikir itu layak secara eksplisit menyebutkan persyaratan hanya untuk satu asal, karena standar W3C memang memungkinkan untuk daftar yang dipisahkan ruang - tetapi Chrome tidak! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB bit "dalam praktik".

wombling - Chris Paine
sumber
41

Masukkan ini ke dalam fungsi init Anda:

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

Itu akan berhasil.

Alex Athlan
sumber
1
Kamu menyelamatkan hariku! Pada level metode withCredentials tidak bekerja untuk saya. Tapi secara global seperti ini akhirnya berhasil! Terima kasih.
Paulius Matulionis
hati-hati dengan itu, karena itu akan mengirim cookie ke semua permintaan, eter untuk domain lain (yang tidak diharapkan ini dan gagal permintaan dengan memerlukan Access-Control-Allow-Credentials)
gdbdable
12

Sudah ada banyak respons yang baik untuk pertanyaan ini, tetapi saya pikir mungkin akan membantu untuk mengklarifikasi kasus di mana Anda akan mengharapkan cookie sesi dikirim karena domain cookie cocok, tetapi itu tidak dikirim karena permintaan AJAX adalah sedang dibuat ke subdomain yang berbeda. Dalam hal ini, saya memiliki cookie yang ditugaskan ke domain * .mydomain.com , dan saya ingin itu dimasukkan dalam permintaan AJAX ke different.mydomain.com ". Secara default, cookie tidak dapat dikirim. Anda tidak perlu menonaktifkan HTTPONLY pada cookie sesi untuk menyelesaikan masalah ini. Anda hanya perlu melakukan apa yang disarankan wombling ( https://stackoverflow.com/a/23660618/545223 ) dan lakukan hal berikut.

1) Tambahkan yang berikut ini ke permintaan ajax Anda.

xhrFields: { withCredentials:true }

2) Tambahkan yang berikut ke header respons Anda untuk sumber daya di subdomain yang berbeda.

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

Setelah mencoba solusi lain dan masih belum berhasil, saya menemukan apa masalahnya dalam kasus saya. Saya mengubah contentType dari "application / json" menjadi "text / plain".

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

Saya mengalami masalah yang sama dan melakukan beberapa pemeriksaan skrip saya hanya tidak mendapatkan cookie sessionid.

Saya menemukan dengan melihat nilai cookie sessionid di browser yang kerangka saya (Django) melewati cookie sessionid dengan HttpOnly sebagai default. Ini berarti bahwa skrip tidak memiliki akses ke nilai sessionid dan karenanya tidak meneruskannya bersama dengan permintaan. Agak konyol bahwa HttpOnly akan menjadi nilai default ketika begitu banyak hal menggunakan Ajax yang akan memerlukan pembatasan akses.

Untuk memperbaikinya, saya mengubah pengaturan (SESSION_COOKIE_HTTPONLY = Salah) tetapi dalam kasus lain ini mungkin berupa bendera "HttpOnly" di jalur cookie

wiwa
sumber
2
Jangan lakukan ini. Ini memungkinkan akses skrip sisi klien ke cookie sesi yang merupakan vektor serangan XSS paling umum. owasp.org/index.php/HttpOnly
Jason Elkin
1

Jika Anda mengembangkan localhostatau port di localhost seperti localhost:8080, selain langkah-langkah yang dijelaskan dalam jawaban di atas, Anda juga perlu memastikan bahwa Anda tidak melewatkan nilai domain di header Set-Cookie.
Anda tidak dapat mengatur domain ke localhostdalam header Set-Cookie - itu tidak benar - cukup hilangkan domain tersebut.

Lihat Cookie di localhost dengan domain eksplisit dan Mengapa asp.net tidak akan membuat cookie di localhost?

jitin
sumber
0

Hanya 2 sen saya pada pengaturan masalah cookie PHPSESSID ketika di localhost dan di bawah lingkungan dev. Saya membuat panggilan AJAX ke titik akhir REST API saya di locahost. Katakan alamatnya mysite.localhost/api/member/login/(host utama di lingkungan dev saya).

  • Ketika saya melakukan permintaan ini pada tukang pos , semuanya berjalan dengan baik dan PHPSESSID diatur dengan respons.

  • Ketika saya meminta titik akhir ini melalui AJAX dari halaman proksi Browsersync (misalnya dari 122.133.1.110:3000/test/api/login.phpdalam baris alamat browser saya, lihat domainnya berbeda vs mysite.localhost) PHPSESSID tidak muncul di antara cookie.

  • Ketika saya membuat permintaan ini langsung dari halaman di domain yang sama (yaitu mysite.localhost/test/api/login.php) PHPSESSID diatur dengan baik.

Jadi ini adalah masalah cookie permintaan lintas asal asal seperti yang disebutkan dalam jawaban @flu di atas

Valentine Shi
sumber
0

Menambahkan skenario dan solusi saya jika itu membantu orang lain. Saya mengalami kasus serupa ketika menggunakan API ISTIRAHAT. Server Web saya yang menghosting file HTML / Script / CSS dan Server Aplikasi yang mengekspos API dihosting di domain yang sama. Namun jalannya berbeda.

server web - mydomain / halaman web /abc.html

menggunakan abc.js yang mengatur cookie bernama mycookie

server aplikasi - mydomain / webapis / servicename.

dimana panggilan api dilakukan

Saya mengharapkan cookie di mydomain / webapis / servicename dan mencoba membacanya tetapi tidak dikirim. Setelah membaca komentar dari jawabannya, saya memeriksa di alat pengembangan browser bahwa jalur mycookie disetel ke "/ halaman web " dan karenanya tidak tersedia dalam panggilan layanan untuk

mydomain / webapis / servicename

Jadi Saat mengatur cookie dari jquery, ini yang saya lakukan -

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

Mungkin tidak 100% menjawab pertanyaan, tetapi saya menemukan utas ini dengan harapan menyelesaikan masalah sesi ketika ajax-posting fileupload dari assetmanager editor innovastudio. Akhirnya solusinya sederhana: mereka memiliki pengunggah flash. Menonaktifkan itu (pengaturan

var flashUpload = false;   

di asset.php) dan lampu mulai berkedip lagi.

Karena masalah ini bisa sangat sulit untuk di-debug, saya menemukan bahwa menempatkan sesuatu seperti yang berikut ini pada pengunggah pengendali akan membuat Anda (well, saya dalam hal ini) di jalur yang benar:

$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");

Menyelam ke log dan saya dengan cepat melihat sesi yang hilang, di mana tidak ada cookie yang dikirim.

Ellert van Koperen
sumber
Saya tidak berpikir contoh di atas akan berhasil, karena ketika tidak ada cookie sesi, berapakah nilai $ sn? (yang acak, atau mungkin nol), atau pengguna dapat mengatur session_name dari nilai GET misalnya session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();dengan cara ini, mereka akan mendapatkan sesuatu yang berfungsi
Steel Brain
Persis seperti itulah saya menemukan masalah: tidak ada sesi saat memposting dari pengunggah flash ini. Karena menggunakan pengidentifikasi sesi variabel GET adalah ide yang buruk, dan cookie tidak berfungsi, saya membuangnya. Siapa peduli, flash adalah sesuatu dari masa lalu.
Ellert van Koperen