我有一个网页,我希望在用户登录时重新生成会话ID。我遇到的问题是我运行session_regenerate_id();
然后尝试附加$_SESSION['user'] = $row;
其中$ row是一个数组
我已经尝试了书中的所有内容,例如破坏会话然后重新开始。我一直在研究它至少2个小时,我没有解决方案。
我删除了很多不相关的php并留下了一些内容,所以你得到了我想要做的事情的要点,但这里是脚本
<?php
session_start();
if(!isset($_SESSION["CSRF"])){
$_SESSION["CSRF"] = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 10);
}
if(!empty($_POST)){
if($_POST["action"]==="login"){
//querying DB for $_POST values
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
$login_ok = false;
$row = $stmt->fetch();
if($row){
$checked = //check password is okay
if ($checked) {
$login_ok = true;
}
}
if($login_ok) {
session_regenerate_id();
unset($row['salt']);
unset($row['password']);
$_SESSION['user'] = $row;
}
}
}
我也试过没有运气。
<?php
session_start();
if(!isset($_SESSION["CSRF"])){
$_SESSION["CSRF"] = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 10);
}
if(!empty($_POST)){
if($_POST["action"]==="login"){
//querying DB for $_POST values
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
$login_ok = false;
$row = $stmt->fetch();
if($row){
$checked = //check password is okay
if ($checked) {
$login_ok = true;
}
}
if($login_ok) {
unset($row['salt']);
unset($row['password']);
$_SESSION['user'] = $row;
$arr = $_SESSION;
session_regenerate_id(true);
$_SESSION = $arr;
}
}
}
抱歉,我没有澄清标题,但基本上我会尝试将当前会话存储在一个变量中,我将重新生成会话ID并添加尝试将存储的会话变量添加到新会话中,但是会话ID确实不包含旧数据,我没有收到任何错误。
答案 0 :(得分:1)
我曾经遇到过同样的问题,但这真的只是在黑暗中拍摄,因为它是如此具体的情况。
我有两个域名, www.domain.com 和 secure.domain.com 。当我访问www.domain.com时,它设置了一个cookie,但是在cookie params我将域设置为.domain.com
,这意味着它用于domain.com和所有子域。 / p>
然后在secure.domain.com上,我也使用了会话cookie,但cookie中使用的域名是secure.domain.com
(即它只适用于secure
子域名)。为了检查用户是否已登录,我在if (isset($_SESSION['username']))
行做了一些事情来检查它是否在会话中设置,但是因为domain.com没有使用数组键username
在其会话中,它没有收到会话cookie domain.com。然后当我登录时,我会设置username
并且所有工作完全正常,直到我重新生成会话ID。一旦我这样做,用户立即再次注销。我花了很长时间才弄清楚发生了什么,但基本上我在浏览器上留下了两个会话cookie,一个发送到.domain.com
而另一个发送给{ {1}}他们彼此冲突。
这可以通过两种方式解决:
secure.domain.com
子域,而不是所有子域。session_name()
。这就是我所做的。答案 1 :(得分:0)
你确定$ login_ok设置为true吗?你可以在那里打印一些东西。从我的测试(脚本的简化版本),它似乎工作正常:
<?php
session_start();
$data = $_SESSION['data'];
$sid = session_id();
echo "Old data is $data<br>Sid is $sid<br>";
if($_GET["action"]==="login"){
session_regenerate_id();
$_SESSION['data'] = $data + 1;
}
$data = $_SESSION['data'];
$sid = session_id();
echo "New data is $data\n<br>Sid is $sid\n<br>";
答案 2 :(得分:0)
如果我错了,请纠正我,但为什么要重新分配$ _SESSION的内容? session_regenerate_id()不会使会话内容为空,它只是为会话提供一个新ID - 会话内容仍然与重新生成之前相同。所以没有必要重新分配价值观。
因此,这样做应该是完全有效的:
if($login_ok) {
unset($row['salt']);
unset($row['password']);
$_SESSION['user'] = $row;
session_regenerate_id();
}
无需重新签名。
此外,在开始会话之前,您应该始终检查会话是否已经启动,所以在开始时执行此操作:if (session_id()) { session_start(); }
而不仅仅是session_start()
。