Чому метод .ajax () jquery не надсилає моє сеансове cookie?


338

Після входу через $.ajax()сайт я намагаюся надіслати другий $.ajax()запит на цей сайт, але коли я перевіряю заголовки, надіслані за допомогою FireBug, у запит не включається печиво сеансу.

Що я роблю неправильно?


2
Файл cookie ajax може з’явитися після того, як веб-cookie та FireBug можуть схопити файли cookie на першій сторінці.
Кріс

1
Я не зрозумів, що я маю на увазі, але я можу сказати, якщо я вставити URL-адресу запиту в адресний рядок браузера і ще раз перевірити Firebug, я можу побачити печиво в заголовках, надісланих на сервер. Будь-які рішення?
user345625

Отже, я думаю, що Ajax також буде працювати з таким же способом, як і браузер
user345625

Який код ви використовуєте?
Дін Хардінг

браузер все одно буде створювати файли cookie, встановлені сервером під час запиту ajax, jquery чи іншого. Ви перевірили відповідь на запит ajax і переконалися, що файли cookie повернулися з встановленого сервера? Може виникнути проблема з кодом сервера таким, що він навіть не встановлює файли cookie тощо.
Девід

Відповіді:


218

AJAX-дзвінки надсилають файли cookie лише в тому випадку, якщо URL-адреса, яку ви телефонуєте, знаходиться на тому ж домені, що і ваш сценарій виклику.

Це може бути проблема міждоменної галузі.

Можливо, ви спробували зателефонувати за URL-адресою, www.domain-a.comпоки увімкнено ваш скрипт виклику www.domain-b.com(Іншими словами: ви здійснили перехресний доменний дзвінок, і в такому випадку браузер не надсилає файлів cookie для захисту вашої конфіденційності).

У цьому випадку ваші варіанти:

  • Напишіть невеликий проксі-сервер, який знаходиться на домені-b, і пересилатиме ваші запити до домену-a. Ваш браузер дозволить вам зателефонувати проксі, оскільки він знаходиться на тому ж сервері, що і сценарій виклику.
    Потім цей проксі можна налаштувати, щоб прийняти ім'я файлу cookie та параметр значення, який він може надіслати домену-a. Але для цього вам потрібно знати ім'я файлу cookie та цінувати ваш сервер на домені, який хоче пройти автентифікацію.
  • Якщо ви отримуєте об'єкти JSON, спробуйте скористатись запитом JSONP . jQuery підтримує це. Але вам потрібно змінити службу на домен-а, щоб вона повернула дійсні JSONP відповіді.

Радий, якщо це навіть трохи допомогло.


19
Також варто зауважити, що файли cookie можуть бути встановлені на певний шлях, тому якщо файл cookie було встановлено, path=/somethingі ви запитуєте сторінку, /anotherфайл cookie не надсилатиметься. Коли ви запитаєте сторінку, /somethingфайл cookie буде надіслано, як очікувалося. Тому перевірте код, який встановлює файл cookie.
стайф

2
чи надсилає запит jsonp файли cookie?
альбанкс

1
@albanx Так, якщо встановлені вимоги, які я згадав. Це просто звичайний запит, як і будь-який інший, і як такий надсилає файли cookie.
грип

1
@albanx це інше пов’язане питання включає в себе приклад того, як зробити цей запит JSONP зі спеціальними файлами cookie
AntonioHerraizS

4
Як повідомляє JSONP у Вікіпедії> від цього підходу було відмовлено на користь CORS
Петро Дотчев

388

Я працюю в міждоменному сценарії. Під час входу віддалений сервер повертає заголовок Set-Cookie разом із Access-Control-Allow-Credentialsзначенням true.

Наступний виклик ajax на віддалений сервер повинен використовувати це cookie.

CORS Access-Control-Allow-Credentialsє там, щоб дозволити ведення міждоменного журналу. Перевірте https://developer.mozilla.org/En/HTTP_access_control на приклади.

Для мене це здається помилкою в JQuery (або, принаймні, функцією, яка буде в наступній версії).

ОНОВЛЕННЯ:

  1. Файли cookie не встановлюються автоматично з відповіді AJAX (цитування: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/ )

    Чому?

  2. Ви не можете отримати значення файлу cookie з відповіді, щоб встановити його вручну ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader )

    Я збентежений..

    Повинен існувати спосіб запиту jquery.ajax()встановити XMLHttpRequest.withCredentials = "true"параметр.

ВІДПОВІДЬ: Ви повинні використовувати xhrFieldsпарам http://api.jquery.com/jQuery.ajax/

Приклад в документації:

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

Також важливо, щоб сервер відповідав правильно на цей запит. Скопіюйте сюди чудові коментарі від @ Frédéric та @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: *

Отже, коли запит:

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

Сервер повинен відповідати:

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

[payload]

Інакше корисне навантаження не повернеться до сценарію. Дивіться: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials


8
Чудово! Додаю використовувати цей + встановити заголовок Access-Control-Allow-Credentials істинно на стороні сервера
Frédéric

і де я можу встановити ці Повноважні дані ?, в "Авторизація заголовка", в органі запиту?
Франсіско Корралес Моралес

3
Дякую за відповідь :) лише швидке доповнення, можливо, варто згадати 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

На жаль, нічого з цього не працювало для мене. Якщо я запускаю той самий запит від AngularJS, він працює, але від jQuery, навіть з цими пропозиціями cookie сеансу не передається. (jQuery v2.1.1)
геодезичний

(ОО) Ти врятував мене від різних болісних годин. Яка ідеальна відповідь! Дякую! Мені потрібно було додати їх у відкритий root .htaccess мого веб-сайту: <IfModule mod_headers.c> Набір заголовків Access-Control-Allow-Origin " localhost " Набір заголовків Access-Control-Allow-Credentials "true" </IfModule>
Vinay Vissh

48

Використання

xhrFields: { withCredentials:true }

як частина мого дзвінка ajax jQuery був лише частиною рішення. Мені також потрібно було, щоб заголовки повернулися у відповідь OPTIONS з мого ресурсу:

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

Важливо, щоб у заголовку відповіді на виклик OPTIONS було вказано лише одне дозволене "походження", а не "*". Я домігся цього, прочитавши джерело запиту та заповнивши його у відповідь - ймовірно, обійшовши початкову причину обмеження, але в моєму випадку безпека не є першорядною.

Я подумав, що варто чітко згадати про вимогу лише до одного походження, оскільки стандарт W3C дозволяє використовувати список, розділений пробілом, але Chrome не дозволяє! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB біт "на практиці".


41

Поставте це у своїй функції init:

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

Це спрацює.


1
Ти врятував мій день! На рівні методу withCredentials не працював для мене. Але глобально, як це, нарешті працює! Дякую.
Paulius Matulionis

будьте обережні з цим, тому що він надсилатиме файли cookie на всі запити, ефір для інших доменів (що не очікує цього і не потребує запиту, вимагаючи Access-Control-Allow-Credentials)
gdbdable

12

На це питання вже є багато хороших відповідей, але я подумав, що може бути корисним з’ясувати випадок, коли ви очікуєте, що сесійне cookie буде надіслане, оскільки домен файлу cookie збігається, але він не надсилається, оскільки запит AJAX є перехід на інший субдомен. У цьому випадку у мене є файл cookie, призначений для домену * .mydomain.com , і я хочу, щоб він був включений у запит AJAX на веб-сайт different.mydomain.com ". За замовчуванням файл cookie не надсилається. Щоб вирішити цю проблему, вам не потрібно відключати HTTPONLY у файлі cookie сеансу. Вам потрібно виконати лише те, що запропонував, щоб зробити це ( https://stackoverflow.com/a/23660618/545223 ), і зробити наступне.

1) Додайте наступне до запиту ajax.

xhrFields: { withCredentials:true }

2) Додайте наступне до заголовків відповідей щодо ресурсів у різних субдоменах.

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

7

Спробувавши інші рішення, і все ще не змусив його працювати, я з’ясував, у чому проблема в моєму випадку. Я змінив contentType з "application / json" на "text / plain".

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

4

У мене була ця сама проблема і я робив кілька перевірок, мої сценарії просто не отримували файли cookie.

Я зрозумів, дивлячись на значення файлу cookie sessionid у браузері, що мій фреймворк (Django) передає файли cookie sessionid з HttpOnly за замовчуванням. Це означало, що сценарії не мали доступу до значення sessionid і тому не передавали його разом із запитами. Смішно, що HttpOnly буде типовим значенням, коли так багато речей використовують Ajax, що вимагатиме обмеження доступу.

Щоб виправити це, я змінив налаштування (SESSION_COOKIE_HTTPONLY = Хибне), але в інших випадках це може бути прапор "HttpOnly" на шляху cookie


2
Не роби цього. Це дозволяє клієнтському сценарію отримати доступ до файлу cookie сеансу, який є найпоширенішим вектором атаки XSS. owasp.org/index.php/HttpOnly
Джейсон Елкін

1

Якщо ви розробляєте localhostабо використовуєте порт на localhost, такий як localhost:8080, крім кроків, описаних у відповідях вище, вам також потрібно переконатися, що ви не передаєте значення домену в заголовку Set-Cookie.
Ви не можете встановити домен localhostу заголовку Set-Cookie - це неправильно - просто опустіть домен.

Дивіться файли cookie на localhost з явним доменом і чому asp.net не створить файли cookie у localhost?


0

Тільки мої 2 копійки на встановлення проблеми cookie PHPSESSID, коли він знаходиться у localhost та в середовищі розробників. Я здійснюю виклик AJAX до моєї кінцевої точки API REST в lochost. Скажіть, що його адреса mysite.localhost/api/member/login/(віртуальний господар у моєму середовищі розробників).

  • Коли я роблю цей запит на " Листоноші" , справи йдуть добре, і PHPSESSID встановлюється з відповіддю.

  • Коли я запитую цю кінцеву точку через AJAX зі сторінки проксі-сервера Browsersync (наприклад, 122.133.1.110:3000/test/api/login.phpв адресному рядку мого браузера, див. Домен відрізняється від mysite.localhost). PHPSESSID не з’являється серед файлів cookie.

  • Коли я роблю цей запит безпосередньо зі сторінки в тому ж домені (тобто mysite.localhost/test/api/login.php) PHPSESSID встановлюється просто.

Таким чином, це питання cookie-запиту про походження з різним походженням, як зазначено у відповіді @flu вище


0

Додаю мій сценарій та рішення, якщо це допомагає комусь іншому. Я зіткнувся з подібним випадком під час використання API RESTful. Мій веб-сервер, на якому розміщені файли HTML / Script / CSS, та API-файли серверів додатків, розміщені в одному домені. Однак шлях був іншим.

Веб - сервер - MYDOMAIN / веб - сторінок /abc.html

використовували abc.js, який встановлював файл cookie з ім'ям mycookie

сервер додатків - mydomain / webapis / ім'я служби .

на які були здійснені дзвінки з апі

Я очікував, що файл cookie буде в mydomain / webapis / servicename і спробував його прочитати, але він не надсилався. Прочитавши коментар з відповіді, я перевірив у інструменті розробки браузера, що шлях mycookie встановлено на "/ веб-сторінки " і, отже, недоступний при виклику служби для

мідомен / webapis / ім'я_служби

Отже, встановлюючи файл cookie з jquery, це те, що я зробив -

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

-5

Можливо, не на 100% відповідаючи на питання, але я натрапив на цю нитку з надією вирішити проблему сеансу, коли ajax-опублікував завантаження файлів від менеджера ресурсів редактора inovastudio. Зрештою рішення було простим: у них є флеш-завантажувач. Відключення цього (налаштування

var flashUpload = false;   

в активі.php), і вогні знову почали блимати.

Оскільки ці проблеми можуть бути дуже важкими для налагодження, я виявив, що розміщення чогось подібного в обробнику завантаження поставить вас (ну, я в цьому випадку) на правильний шлях:

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

Занурившись у журнал, і я швидко помітив пропущений сеанс, де жодного файлу cookie не надсилалося.


Я не думаю, що приклад, описаний вище, спрацював би, бо коли немає сеансового файлу cookie, якою буде вартість $ sn? (випадковий або, можливо, нульовий), альтернативно користувачі можуть встановити ім'я session_name з значення GET, наприклад session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();таким чином, вони отримають робочу річ
Steel Brain

Саме так я і знайшов проблему: жоден сеанс при публікації з цього завантажувача флеш-пам’яті. Оскільки використання ідентифікатора змінної сесії GET є поганою ідеєю, а файл cookie не працює, я викинув його. Кому все одно, спалах - це все одно минуле.
Еллерт ван Коперен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.