Ajax正在失去会话

问题描述 投票:5回答:4

我将Symfony应用程序从Symfony 4.0.7升级到Symfony 4.1,之后AJAX调用丢失了会话值。

我同时调用了大约6个ajax请求。其中第一个进展顺利,但其他人正在失去会话价值。它发生在迁移到Symfony 4.1之后,仅用于AJAX调用。有任何想法吗?

编辑:只有在同时调用ajax时才会发生。我在调用ajax之间添加例如100毫秒的延迟然后一切正常。

edit2:它发生在4个不同的服务器上。 2台dev服务器,1台测试服务器和1台实时服务器。所有这些都运行在NGINX和php7上

php symfony symfony4
4个回答
1
投票

可能的原因可能如下::

允许缓存使用会话的请求:

每当在请求期间启动会话时,Symfony都会将响应转换为私有的非可缓存响应,以防止泄露私人信息。但是,即使在某些情况下也可以缓存使用会话的请求。

例如,可以为属于该组的所有用户缓存与某个用户组相关的信息。处理这些高级缓存方案超出了Symfony的范围,但可以使用FOSHttpCacheBundle解决它们。

为了禁用使用会话无法缓存的请求的默认Symfony行为,在Symfony 4.1中我们添加了可以添加到响应的NO_AUTO_CACHE_CONTROL_HEADER标头:

use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');

弃用Request :: getSession()的一些用法

在没有会话时使用Request :: getSession()已在Symfony 4.1中弃用,它将在Symfony 5.0中引发异常。解决方案是始终首先检查Request :: hasSession()方法是否存在会话:

if ($request->hasSession() && ($session = $request->getSession())) {
    $session->set('some_key', 'some_value');
}

更多关于Ref:Here


1
投票

你检查过XMLHttpRequest.withCredentials吗?

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

响应标题怎么样?

  1. Access-Control-Allow-Credentials:true
  2. 连接:保持活力
  3. set-cookie:...

这些请求的会话ID是否相等?

http://php.net/manual/en/function.session-id.php

也许您需要在ajax请求之前设置会话cookie。

这是一个例子:

ajax.php

<?php
function getSessionIdentifier()
{
    if (!session_id()) {
        session_start();
    }
    if (!isset($_SESSION['identifier'])) {
        $_SESSION['identifier'] = bin2hex(random_bytes(5));
    }
    return $_SESSION['identifier'];
}

echo json_encode([
    'identifier' => getSessionIdentifier()
]);

启动无-session.php文件

<!DOCTYPE html>
<html>
<head><title>start without session</title></head>
<body>
<script>
let started;
const cookie = () => '[' + document.cookie + ']';
const track = () => {
    started = started || (new Date()).getTime();
    return ((new Date()).getTime() - started) + 'ms';
};

const send = (index) => {
    const req = new XMLHttpRequest();
    req.open('GET', '/ajax.php');

    console.log(track(), 'send', index, cookie());

    req.addEventListener("load", () => {
        console.log(track(), 'receive', index, cookie(), req.responseText);
    });

    req.send();
}

document.cookie = "PHPSESSID=;expires=Thu, 01 Jan 1970 00:00:00 GMT";

console.log(track(), 'begin', cookie());
const len1 = 5;
const len2 = 10;
Array.from({length: len1}).forEach((v, i) => send(i));
console.log(track(), 'delay');
Array.from({length: len2}).forEach((v, j) => window.setTimeout(() => send(j + len1), j * 10));
</script>
</body></html>

enter image description here

启动与-session.php文件

<?php
session_start();
$_SESSION['identifier'] = bin2hex(random_bytes(5));
?><!DOCTYPE html>
<html>
<head><title>start with session</title></head>
<body>
<script>
let started;
const cookie = () => '[' + document.cookie + ']';
const track = () => {
    started = started || (new Date()).getTime();
    return ((new Date()).getTime() - started) + 'ms';
};

const send = (index) => {
    const req = new XMLHttpRequest();
    req.open('GET', '/ajax.php');

    console.log(track(), 'send', index, cookie());

    req.addEventListener("load", () => {
        console.log(track(), 'receive', index, cookie(), req.responseText);
    });

    req.send();
}

//
// document.cookie = "PHPSESSID=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
//

console.log(track(), 'begin', cookie());
const len1 = 5;
const len2 = 10;
Array.from({length: len1}).forEach((v, i) => send(i));
console.log(track(), 'delay');
Array.from({length: len2}).forEach((v, j) => window.setTimeout(() => send(j + len1), j * 10));
</script>
</body></html>

enter image description here

我不是百分百肯定这是同样的情况。需要更多信息。


1
投票

好的,所以问题是因为会话固定策略正在改变会话ID,每个请求和AJAX请求都有时间更新新ID。

解决方案非常简单,只需设置session_fixation_strategy: none即可。


0
投票

当您的应用程序依赖于实时cookie时,您不能在同一时间启动所有AJAX请求。也许symfony使用cookie中的某些东西来完成CSRF令牌的工作。

它在请求之间100毫秒超时的原因是第一个有时间解析响应并使用该响应更改cookie,下一个请求使用新cookie。

你需要做的是:

  • 使第二个AJAX调用从第一个回调,第三个回调从第二个调用,依此类推......

要么

  • 找出需要更新的cookie中的内容,以便不生成错误并禁用它。但请记住,由于某种原因,此保护已到位,如果禁用,您可能会将您的应用程序暴露给安全漏洞。如果您提供错误的AJAX调用响应(在浏览器中为inpect-> network),它可能有助于我们解决问题

要么

  • 让你的ajax调用使用基于JWT的中间件(如果你以前从未做过,那就太复杂了)所以它使用无状态会话。
© www.soinside.com 2019 - 2024. All rights reserved.