Por que o método .ajax () do jquery não está enviando meu cookie de sessão?


338

Depois de fazer login em $.ajax()um site, estou tentando enviar uma segunda $.ajax()solicitação para esse site - mas quando verifico os cabeçalhos enviados usando o FireBug, não há nenhum cookie de sessão sendo incluído na solicitação.

O que estou fazendo errado?


2
O cookie do ajax pode vir após o cookie da Web e o FireBug pode capturar o cookie da primeira página.
— Chris

11
Eu não entendi o que você quer dizer, mas posso dizer que se colar o URL da solicitação na barra de endereços do navegador e verificar o Firebug novamente, posso ver o cookie nos cabeçalhos enviados ao servidor. Alguma solução?
— User345625

Então, eu acho ajax também irá lidar com mesmo navegador maneira faz
— user345625

Qual é o código que você está usando?
— Dean Harding

o navegador ainda criará cookies configurados pelo servidor durante uma solicitação ajax, jquery ou outro. Você verificou a resposta à solicitação do ajax e garantiu que os cookies voltassem do servidor para serem configurados? Não poderia haver um problema com o código do servidor de tal forma que nem sequer é definir o cookie, etc.
— David

Respostas:


218

As chamadas AJAX apenas enviam cookies se o URL que você está chamando estiver no mesmo domínio que o seu script de chamada.

Este pode ser um problema entre domínios.

Talvez você tenha tentado ligar para um URL www.domain-a.comenquanto o script de chamada estava ativado www.domain-b.com(em outras palavras: você fez uma chamada entre domínios; nesse caso, o navegador não envia cookies para proteger sua privacidade).

Nesse caso, suas opções são:

  • Escreva um pequeno proxy que resida no domínio-b e encaminhe suas solicitações para o domínio-a. Seu navegador permitirá que você chame o proxy porque está no mesmo servidor que o script de chamada.
    Esse proxy pode então ser configurado por você para aceitar um nome de cookie e um parâmetro de valor que pode ser enviado ao domínio-a. Mas, para que isso funcione, você precisa saber o nome do cookie e avaliar seu servidor no domínio - a quer autenticação.
  • Se você estiver buscando objetos JSON, tente usar uma solicitação JSONP . O jQuery suporta isso. Mas você precisa alterar seu serviço no domínio-a para que ele retorne respostas JSONP válidas.

Ainda bem que isso ajudou um pouco.


19
Também é importante notar que os cookies podem ser configurados para um caminho específico; portanto, se você definiu o cookie path=/somethinge está solicitando a página /another, o cookie não será enviado. Quando você solicita a página, /somethingo cookie será enviado conforme o esperado. Portanto, verifique o código que define o cookie também.
— styfle

2
uma solicitação jsonp envia coockies?
— albanx

11
@ albanx Sim, se os requisitos que eu mencionei estiverem definidos. É apenas uma solicitação normal como qualquer outra e, como tal, envia cookies.
— flu

11
@albanx esta outra questão relacionada inclui um exemplo de como fazer essa solicitação JSONP com cookies personalizados
— AntonioHerraizS

4
De acordo com JSONP em Wikipedia> esta abordagem foi abandonada em favor de CORS
— Peter Dotchev

387

Estou operando no cenário entre domínios. Durante o login, o servidor remoto está retornando o cabeçalho Set-Cookie junto com Access-Control-Allow-Credentialsset como true.

A próxima chamada ajax para o servidor remoto deve usar esse cookie.

Os CORS Access-Control-Allow-Credentialsestão lá para permitir o registro entre domínios. Verifique https://developer.mozilla.org/En/HTTP_access_control para obter exemplos.

Para mim, parece um bug no JQuery (ou pelo menos um recurso na próxima versão).

ATUALIZAR:

  1. Os cookies não são definidos automaticamente a partir da resposta AJAX (citação: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/ )

    Por quê?

  2. Você não pode obter o valor do cookie da resposta para defini-lo manualmente ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader )

    Estou confuso..

    Deve haver uma maneira de pedir jquery.ajax()para definir o XMLHttpRequest.withCredentials = "true"parâmetro.

RESPOSTA: Você deve usar o xhrFieldsparâmetro http://api.jquery.com/jQuery.ajax/

O exemplo na documentação é:

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

Também é importante que o servidor responda corretamente a essa solicitação. Copiando aqui ótimos comentários de @ Frédéric e @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: *

Então, quando a solicitação é:

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

O servidor deve responder com:

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

[payload]

Caso contrário, a carga útil não será retornada ao script. Consulte: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials


8
Ótimo ! Acrescento para usar esta + set Access-Control-Allow-Credenciais cabeçalho para true no lado do servidor
— Frédéric

e onde eu defino essas credenciais?, na Autorização de cabeçalho?, no corpo da solicitação?
— Francisco Corrales Morales

3
Obrigado pela resposta :) apenas uma adição rápida, pode valer a pena mencionar 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

Infelizmente, nada disso funcionou para mim. Se eu executar o mesmo pedido do AngularJS, ele funciona, mas do jQuery, mesmo com essas sugestões, a sessão Cookie não é passada. (jQuery v2.1.1)
— geoidesic

(OO) Você me salvou de várias horas dolorosas. Que resposta perfeita! Obrigado! Eu precisava adicioná-los na raiz pública .htaccess do meu site: <IfModule mod_headers.c> Conjunto de cabeçalhos Access-Control-Allow-Origin " localhost " Conjunto de cabeçalhos Access-Control-Allow-Credentials "true" </IfModule>
— Vinay Vissh

48

Usando

xhrFields: { withCredentials:true }

como parte da minha chamada jQuery ajax era apenas parte da solução. Eu também precisava ter os cabeçalhos retornados na resposta OPTIONS do meu recurso:

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

Era importante que apenas uma "origem" permitida estivesse no cabeçalho de resposta da chamada OPTIONS e não "*". Consegui isso lendo a origem da solicitação e preenchendo-a novamente na resposta - provavelmente contornando o motivo original da restrição, mas, no meu caso de uso, a segurança não é fundamental.

Eu pensei que vale a pena mencionar explicitamente o requisito para apenas uma origem, pois o padrão W3C permite uma lista separada por espaço - mas o Chrome não! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB o bit "na prática".


41

Coloque isso na sua função init:

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

Vai funcionar.


11
Você salvou meu dia! No nível do método withCredentials, não funcionou para mim. Mas globalmente assim, finalmente funciona! Obrigado.
— Paulius Matulionis

ter cuidado com ele, porque ele irá enviar cookies para todas as solicitações, éter para outros domínios (que não é de esperar isso e deixar pedido exigir credenciais de Access-Control-Allow-)
— gdbdable

12

Já existem muitas respostas boas para essa pergunta, mas achei útil esclarecer o caso em que você espera que o cookie da sessão seja enviado porque o domínio do cookie corresponde, mas não está sendo enviado porque a solicitação AJAX é sendo feito para um subdomínio diferente. Nesse caso, tenho um cookie atribuído ao domínio * .mydomain.com e pretendo que ele seja incluído em uma solicitação AJAX para different.mydomain.com ". Por padrão, o cookie não é enviado. Você não precisa desabilitar o HTTPONLY no cookie da sessão para resolver esse problema. Você só precisa fazer o que sugeriu wombling ( https://stackoverflow.com/a/23660618/545223 ) e fazer o seguinte.

1) Adicione o seguinte ao seu pedido de ajax.

xhrFields: { withCredentials:true }

2) Adicione o seguinte aos seus cabeçalhos de resposta para obter recursos nos diferentes subdomínios.

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

7

Depois de experimentar as outras soluções e ainda não fazê-lo funcionar, descobri qual era o problema no meu caso. Alterei contentType de "application / json" para "text / plain".

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

4

Eu estava tendo o mesmo problema e, ao fazer algumas verificações, meu script simplesmente não estava recebendo o cookie sessionid.

Eu descobri olhando para o valor do cookie sessionid no navegador que minha estrutura (Django) estava passando o cookie sessionid com o HttpOnly como padrão. Isso significava que os scripts não tinham acesso ao valor sessionid e, portanto, não o passavam junto com os pedidos. É ridículo que HttpOnly seja o valor padrão quando tantas coisas usam o Ajax, o que exigiria restrição de acesso.

Para corrigir isso, alterei uma configuração (SESSION_COOKIE_HTTPONLY = False), mas em outros casos pode ser um sinalizador "HttpOnly" no caminho do cookie


2
Não faça isso. Ele permite que o script do lado do cliente acesse o cookie da sessão, que é o vetor de ataque XSS mais comum. owasp.org/index.php/HttpOnly
— Jason Elkin


0

Apenas meus 2 centavos na configuração do problema de cookie PHPSESSID quando estiver no host local e no ambiente de desenvolvimento. Eu faço a chamada AJAX para o meu ponto de extremidade da API REST no locahost. Digamos que seu endereço seja mysite.localhost/api/member/login/(host virtual no meu ambiente de desenvolvimento).

  • Quando faço essa solicitação no Postman , as coisas correm bem e o PHPSESSID é definido com a resposta.

  • Quando solicito esse endpoint via AJAX na página em proxy do Browsersync (por exemplo, 122.133.1.110:3000/test/api/login.phpna linha de endereço do meu navegador, veja se o domínio é diferente mysite.localhost), o PHPSESSID não aparece entre os cookies.

  • Quando faço esse pedido diretamente da página no mesmo domínio (por exemplo mysite.localhost/test/api/login.php), o PHPSESSID está definido corretamente.

Portanto, este é um problema de cookies de solicitação de origem de origem cruzada, conforme mencionado na resposta @flu acima


0

Adicionando meu cenário e solução, caso isso ajude outra pessoa. Encontrei um caso semelhante ao usar APIs RESTful. Meu servidor da Web que hospeda arquivos HTML / Script / CSS e APIs de exposição do Application Server foram hospedados no mesmo domínio. No entanto, o caminho foi diferente.

servidor web - meudomínio / páginas da web /abc.html

usou o abc.js que define o cookie chamado mycookie

servidor de aplicativos - meudominio / webapis / servicename.

para o qual as chamadas da API foram feitas

Eu estava esperando o cookie em meudomínio / webapis / servicename e tentei lê-lo, mas ele não estava sendo enviado. Depois de ler o comentário da resposta, verifiquei na ferramenta de desenvolvimento do navegador que o caminho do mycookie estava definido como "/ páginas da web " e, portanto, não estava disponível na chamada de serviço para

mydomain / webapis / servicename

Então, ao definir o cookie do jquery, foi o que eu fiz -

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

-5

Talvez não esteja 100% respondendo à pergunta, mas me deparei com esse tópico na esperança de resolver um problema de sessão ao postar ajax um upload de arquivo do gerenciador de ativos do editor innovastudio. Eventualmente, a solução foi simples: eles têm um flash-uploader. Desativando isso (configuração

var flashUpload = false;   

em asset.php) e as luzes começaram a piscar novamente.

Como esses problemas podem ser muito difíceis de depurar, descobri que colocar algo como o seguinte no manipulador de upload definirá você (bem, eu neste caso) no caminho certo:

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

Mergulhei no registro e rapidamente localizei a sessão ausente, onde nenhum cookie foi enviado.


Eu não acho que o exemplo acima funcionaria, porque quando não há cookie de sessão, qual seria o valor de $ sn? (um acaso, ou talvez nulo), alternativamente, os usuários podem definir session_name de um valor GET por exemplo session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();desta forma, eles teriam uma coisa trabalhando
— Aço Cérebro

Foi exatamente assim que encontrei o problema: nenhuma sessão ao postar algo desse carregador de flash. Como usar um identificador de sessão variável GET é uma má idéia, e o cookie não estava funcionando, eu joguei fora. Quem se importa, o flash é uma coisa do passado de qualquer maneira.
— Ellert van Koperen
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.