我正在用 PHP 构建一种网络应用程序。我有一个登录表单,我将令牌存储在会话变量中,该变量基本上告诉服务器用户在线(这也存储在数据库中)。当显示登录表单时(新登录...或注销 - 此处代码中未显示),此令牌会清除。我还在成功登录时将 session_id() 存储在数据库中。
为了防止打开 2 个会话(在相同的浏览器或不同的浏览器中),我做了 2 种检查:
用户是否只在登录后打开第二个选项卡,我检查此令牌和 http 引荐来源网址。如果令牌不为空(意味着有人已登录)并且 http 引荐来源为空(意味着已打开一个新选项卡/窗口),我会回显一条错误消息(“您已经有一个打开的会话......”)。
用户在登录之前是否会打开 2 个选项卡,我会检查数据库中的这个令牌和 session_id() 以及当前的。如果令牌在那里(意味着有人登录)并且数据库和当前 session_id() 相同(意味着我们仍在同一个浏览器中),我会回显一条错误消息(“你已经有一个打开的会话.. 。”)。session_id() 在这里会不会有所不同,这意味着我们在另一个浏览器中,我也在检查这个。
同时,我试图阻止用户重新发布登录表单,这意味着,我希望他们避免在登录后立即点击重新加载。
问题:
使用上面的设置,如果我点击重新加载,服务器会认为它是第二个浏览器选项卡登录(上面的案例#2),因为令牌将在那里并且 session_id() 也将是相同的,所以它将回显错误消息(“您已经有一个打开的会话......”)。
有没有办法结合起来并确保在登录表单重新加载时没有任何反应?
代码看起来像这样(我试图从不必要的代码中删除它,如果它不是 100% 正确,请见谅):
<?php function LoginForm() {
$_SESSION['token'] = ''; ?>
<form action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING']); ?>" method="post">
Please enter your login details</div><br />
Login ID<br />
<input type="text" name="userid" /><br /><br />
Password<br />
<input type="password" name="password" /><br /><br />
<input type="submit" name="login" value="Login" />
</form>
<?php }
if (!empty($token_in_DB) AND !isset($_SERVER['HTTP_REFERER'])) {
echo "You are already logged in on another tab / window";
exit();
} elseif (isset($_POST['login'])) {
if (!empty($token_in_DB)) {
if ($session_in_DB == session_id()) {
echo "You are already logged in on another tab / window";
exit();
} else {
echo "You are already logged in on another browser / computer";
exit();
}
} elseif (/* password is ok */) {
// login
// set token session variable
// add token to db
}
} elseif (empty($_SESSION['token'])) {
LoginForm();
} ?>