web-dev-qa-db-fra.com

Pourquoi la méthode .ajax () de jquery n'envoie-t-elle pas mon cookie de session?

Après avoir ouvert une session via $.ajax() sur un site, j'essaie d'envoyer une deuxième demande $.ajax() à ce site. Toutefois, lorsque je vérifie les en-têtes envoyés à l'aide de FireBug, aucun cookie de session n'est inclus dans la demande.

Qu'est-ce que je fais mal?

309
user345625

Les appels AJAX envoient uniquement des cookies si l'URL que vous appelez se trouve sur le même domaine que votre script d'appel.

Cela peut être un problème interdomaine.

Peut-être avez-vous essayé d'appeler une URL à partir de www.domain-a.com alors que votre script d'appel était sur www.domain-b.com (autrement dit: vous avez passé un appel interdomaine, auquel cas le navigateur n'enverra aucun cookie pour protéger votre confidentialité).

Dans ce cas, vos options sont les suivantes:

  • Ecrivez un petit proxy qui réside sur le domaine-b et transmettez vos demandes à domaine-a. Votre navigateur vous permettra d'appeler le proxy car il se trouve sur le même serveur que le script d'appel.
    Ce proxy peut alors être configuré par vous pour accepter un nom de cookie et un paramètre de valeur qu’il peut envoyer à domain-a. Mais pour que cela fonctionne, vous devez connaître le nom du cookie et attribuer une valeur à votre serveur sur le domaine, ce qui nécessite une authentification.
  • Si vous récupérez des objets JSON, essayez plutôt d’utiliser une requête JSONP . jQuery les prend en charge. Mais vous devez modifier votre service sur le domaine-a afin qu'il renvoie des réponses JSONP valides.

Glad si cela a aidé même un peu.

199
flu

Je travaille dans un scénario interdomaine. Pendant la connexion, le serveur distant renvoie l'en-tête Set-Cookie avec Access-Control-Allow-Credentials défini sur true.

Le prochain appel ajax au serveur distant devrait utiliser ce cookie.

Le Access-Control-Allow-Credentials de CORS est là pour permettre la journalisation entre domaines. Consultez https://developer.mozilla.org/En/HTTP_access_control pour des exemples.

Pour moi, cela ressemble à un bogue dans JQuery (ou au moins une fonctionnalité dans la prochaine version).

METTRE À JOUR:

  1. Les cookies ne sont pas configurés automatiquement à partir de la réponse AJAX (citation: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/ )

    Pourquoi?

  2. Vous ne pouvez pas obtenir la valeur du cookie de la réponse pour le définir manuellement ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader )

    Je suis confus..

    Il devrait exister un moyen de demander à jquery.ajax() de définir le paramètre XMLHttpRequest.withCredentials = "true".

REPONSE: Vous devriez utiliser xhrFields param de http://api.jquery.com/jQuery.ajax/

L'exemple dans la documentation est:

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

Il est également important que le serveur réponde correctement à cette demande. Copier ici d'excellents commentaires de @ Frédéric et @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: *

Alors, quand la demande est:

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

Le serveur devrait répondre avec:

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

[payload]

Sinon, les données utiles ne seront pas renvoyées au script. Voir: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials

355
Kangur

En utilisant

xhrFields: { withCredentials:true }

dans le cadre de mon appel jQuery ajax n'était qu'une partie de la solution. J'avais également besoin que les en-têtes soient renvoyés dans la réponse OPTIONS de ma ressource:

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

Il était important que seul one autorisé "Origine" figure dans l'en-tête de réponse de l'appel OPTIONS et que not "*". J'ai atteint cet objectif en lisant l'origine dans la requête et en l'enrichissant dans la réponse - contournant probablement le motif initial de la restriction, mais dans mon cas d'utilisation, la sécurité n'est pas primordiale. 

Je pensais qu'il valait la peine de mentionner explicitement l'exigence relative à une seule origine, car le standard W3C autorise une liste séparée par des espaces - mais pas Chrome! http://www.w3.org/TR/cors/# accès-contrôle-autoriser-en-tête-réponse-origine NB le bit "en pratique".

46

Mettez ceci dans votre fonction init: 

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

Ça va marcher.

38
Alex Athlan

Il y a déjà beaucoup de bonnes réponses à cette question, mais j’ai pensé qu’il serait peut-être utile de préciser le cas dans lequel vous vous attendez à ce que le cookie de session soit envoyé parce que le domaine de cookie correspond, mais il n’est pas envoyé parce que AJAX la demande est adressée à un sous-domaine différent. Dans ce cas, j'ai un cookie affecté au domaine * .mydomain.com et je souhaite l'inclure dans une AJAX demande à different.mydomain.com. ". Par défaut, le cookie n'est pas envoyé. Il n'est pas nécessaire de désactiver HTTPONLY sur le cookie de session pour résoudre ce problème. Vous devez uniquement faire ce que wombling a suggéré ( https://stackoverflow.com/a/23660618/545223 ) et procédez comme suit.

1) Ajoutez ce qui suit à votre demande ajax.

xhrFields: { withCredentials:true }

2) Ajoutez ce qui suit dans vos en-têtes de réponse pour les ressources des différents sous-domaines.

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

Après avoir essayé les autres solutions sans réussir à le faire, j'ai découvert quel était le problème dans mon cas. J'ai changé contentType de "application/json" à "text/plain".

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

J'avais le même problème et en vérifiant mon script, je ne recevais tout simplement pas le cookie sessionid.

J'ai découvert, en consultant la valeur du cookie sessionid dans le navigateur, que mon framework (Django) transmettait le cookie sessionid avec HttpOnly par défaut. Cela signifiait que les scripts n'avaient pas accès à la valeur sessionid et ne la transmettaient donc pas avec les demandes. C'est un peu ridicule que HttpOnly soit la valeur par défaut lorsque tant de choses utilisent Ajax, ce qui nécessiterait une restriction d'accès. 

Pour résoudre ce problème, j'ai modifié un paramètre (SESSION_COOKIE_HTTPONLY = False), mais dans d'autres cas, il peut s'agir d'un indicateur "HttpOnly" sur le chemin du cookie.

3
wiwa

Si vous développez sur localhost ou un port sur localhost tel que localhost:8080, en plus des étapes décrites dans les réponses ci-dessus, vous devez également vous assurer que vous ne transmettez pas une valeur de domaine dans l'en-tête Set-Cookie.
Vous ne pouvez pas définir le domaine sur localhost dans l'en-tête Set-Cookie - c'est incorrect - omettez simplement le domaine. 

Voir Cookies sur localhost avec domaine explicite et Pourquoi asp.net ne crée-t-il pas de cookies sur localhost?

0
jitin

Juste mes 2 centimes sur la définition du problème de cookie PHPSESSID dans les environnements localhost et dev. Je passe l'appel AJAX à mon point de terminaison d'API REST sur le locahost. Dites que son adresse est mysite.localhost/api/member/login/ (hôte virtuel sur mon environnement de développement).

  • Lorsque je fais cette demande sur Postman , tout va bien et PHPSESSID est défini avec la réponse.

  • Lorsque je demande ce point de terminaison via AJAX à partir de la page proxy de Browsersync (par exemple, à partir de 122.133.1.110:3000/test/api/login.php dans la ligne d'adresse de mon navigateur, le domaine est différent de mysite.localhost). PHPSESSID n'apparaît pas parmi les cookies.

  • Lorsque je fais cette demande directement à partir de la page du même domaine (c'est-à-dire mysite.localhost/test/api/login.php), PHPSESSID est correctement défini.

Il s'agit donc d'un problème de cookies de demande d'origine croisée, comme indiqué dans @flu réponse ci-dessus

0
bob-12345