Почему метод jaery .ajax () не отправляет мой сеансовый cookie?


338

После входа в систему через $.ajax()сайт я пытаюсь отправить второй $.ajax()запрос на этот сайт, но когда я проверяю заголовки, отправленные с помощью FireBug, в запрос не включается файл cookie сеанса.

Что я делаю не так?


2
Файл cookie ajax может появиться после веб-файла cookie, и FireBug может перехватить файл cookie первой страницы.
Крис

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

Итак, я думаю, что ajax будет обрабатывать так же, как браузер
user345625

Какой код вы используете?
Дин Хардинг

браузер по-прежнему будет создавать файлы cookie, установленные сервером во время запроса ajax, jquery или иным образом. Вы проверили ответ на запрос ajax и убедились, что файлы cookie возвращаются с сервера, который нужно настроить?
David

Ответы:


218

Вызовы AJAX отправляют Cookies только в том случае, если URL-адрес, по которому вы звоните, находится в том же домене, что и ваш скрипт вызова.

Это может быть междоменной проблемой.

Возможно, вы пытались вызвать URL-адрес, www.domain-a.comкогда был включен сценарий вызова www.domain-b.com(другими словами: вы сделали междоменный вызов, и в этом случае браузер не будет отправлять файлы cookie для защиты вашей конфиденциальности).

В этом случае ваши варианты:

  • Напишите небольшой прокси, который находится на домене-b и перенаправляет ваши запросы на домен-a. Ваш браузер позволит вам вызывать прокси, потому что он находится на том же сервере, что и вызывающий скрипт.
    Затем вы можете настроить этот прокси-сервер так, чтобы он принимал имя файла cookie и параметр значения, которые он может отправлять в домен a. Но для того, чтобы это работало, вам нужно знать имя куки-файла и значение вашего сервера в домене-a, требующем аутентификации.
  • Если вы выбираете объекты JSON, попробуйте вместо этого использовать запрос JSONP . JQuery поддерживает это. Но вам нужно изменить свой сервис в домене-a, чтобы он возвращал действительные ответы JSONP.

Рад, что это помогло хоть немного.


19
Стоит также отметить, что файлы cookie могут быть установлены по определенному пути, поэтому, если для файла cookie установлено значение path=/somethingи вы запрашиваете страницу, /anotherфайл cookie не будет отправлен. Когда вы запрашиваете страницу, /somethingкуки будут отправлены, как ожидалось. Так что проверьте код, который также устанавливает cookie.
Styfle

2
JSONP-запрос отправляет куки?
albanx

1
@albanx Да, если указанные выше требования установлены. Это обычный запрос, как и любой другой, который отправляет куки.
грипп

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. Вы не можете получить значение куки из ответа, чтобы установить его вручную ( 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 в значение true на стороне сервера
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)
геоидезическая

(OO) Вы спасли меня от различных мучительных часов. Какой идеальный ответ! Спасибо! Мне нужно было добавить их в общий корневой каталог .htaccess моего веб-сайта: <IfModule mod_headers.c> Набор заголовков Access-Control-Allow-Origin " localhost " Набор заголовков Access-Control-Allow-Credentials "true" </ IfModule>
Vinay Vissh

48

С помощью

xhrFields: { withCredentials:true }

как часть моего вызова jQuery ajax была только частью решения. Мне также нужно было вернуть заголовки в ответе 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

Поместите это в вашу функцию инициализации:

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

Это сработает.


1
Ты спас мой день! На уровне метода withCredentials у меня не работает. Но глобально, как это, это наконец работает! Спасибо.
Паулюс Матулионис

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

12

На этот вопрос уже есть много хороших ответов, но я подумал, что было бы полезно прояснить случай, когда вы ожидаете, что cookie-файл сеанса будет отправлен, потому что домен cookie-файлов совпадает, но он не отправляется, потому что запрос AJAX делается на другой поддомен. В этом случае, у меня есть печенье , который назначен на * .mydomain.com домена, и я хотел , чтобы быть включенным в запросе AJAX к different.mydomain.com ». По умолчанию, куки не присылают. Вам не нужно отключать 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-файл sessionid.

По значению cookie-файла sessionid в браузере я выяснил, что мой фреймворк (Django) передавал cookie-файл sessionid с HttpOnly по умолчанию. Это означало, что скрипты не имели доступа к значению sessionid и поэтому не передавали его вместе с запросами. Довольно смешно, что HttpOnly будет значением по умолчанию, когда так много вещей используют Ajax, что потребует ограничения доступа.

Чтобы исправить это, я изменил настройку (SESSION_COOKIE_HTTPONLY = False), но в других случаях это может быть флаг «HttpOnly» на пути к cookie


2
Не делай этого. Это позволяет клиентскому сценарию получить доступ к куки-файлу сеанса, который является наиболее распространенным вектором атаки XSS. owasp.org/index.php/HttpOnly
Джейсон Элкин

1

Если вы разрабатываете localhostпорт или локальный хост, например localhost:8080, в дополнение к шагам, описанным в ответах выше, вам также нужно убедиться, что вы не передаете значение домена в заголовке Set-Cookie.
Вы не можете установить домен localhostв заголовке Set-Cookie - это неправильно - просто опустите домен.

См. Cookies на локальном хосте с явным доменом и Почему asp.net не создает куки на локальном хосте?


0

Просто мои 2 цента при установке файла cookie PHPSESSID при работе на локальном хосте и в среде разработчика. Я делаю AJAX-вызов к моей конечной точке REST API на locahost. Скажите, что его адрес mysite.localhost/api/member/login/(виртуальный хост в моей среде разработки).

  • Когда я делаю этот запрос на Почтальон , все идет хорошо, и PHPSESSID устанавливается с ответом.

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

  • Когда я делаю этот запрос прямо со страницы в том же домене (то есть mysite.localhost/test/api/login.php) PHPSESSID устанавливается просто отлично.

Так что это проблема с файлами cookie для запросов на отправку из разных источников, как упоминалось в ответе @flu выше


0

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

веб-сервер - mydomain / webpages /abc.html

использовал abc.js, который установил cookie с именем mycookie

сервер приложений - mydomain / webapis / servicename .

на которые были сделаны вызовы API

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

mydomain / webapis / servicename

Так что, устанавливая cookie из jquery, я так и сделал -

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

-5

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

var flashUpload = false;   

в asset.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 сеанса, каким будет значение $ sn? (случайный или, может быть, ноль), в качестве альтернативы пользователи могут установить session_name из значения GET, например, session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();таким образом, они получат работающую вещь
Steel Brain

Это именно то, как я нашел проблему: нет сессий при отправке с этого Flash Uploader вещь. Поскольку использование идентификатора сеанса переменной GET - плохая идея, и cookie не работает, я его выбросил. Кого волнует, вспышка остается в прошлом в любом случае.
Эллерт ван Коперен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.