0

我正在用 PHP 构建一种网络应用程序。我有一个登录表单,我将令牌存储在会话变量中,该变量基本上告诉服务器用户在线(这也存储在数据库中)。当显示登录表单时(新登录...或注销 - 此处代码中未显示),此令牌会清除。我还在成功登录时将 session_id() 存储在数据库中。

为了防止打开 2 个会话(在相同的浏览器或不同的浏览器中),我做了 2 种检查:

  1. 用户是否只在登录后打开第二个选项卡,我检查此令牌和 http 引荐来源网址。如果令牌不为空(意味着有人已登录)并且 http 引荐来源为空(意味着已打开一个新选项卡/窗口),我会回显一条错误消息(“您已经有一个打开的会话......”)。

  2. 用户在登录之前是否会打开 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();
} ?>
4

1 回答 1

2

同时,我试图阻止用户重新发布登录表单,这意味着,我希望他们避免在登录后立即点击重新加载。

为了防止这种情况,您应该遵循POST-Redirect-GET模式并在成功 POST 后始终重定向。即如果登录成功,将他们重定向到启动页面或主页等。

其次,如果用户通过另一个选项卡登录并浏览,他或她将拥有与第一个选项卡相同的会话 ID。除非他们打开了新的隐私浏览/隐身窗口,或者他们正在使用代理。

于 2013-07-05T10:48:32.013 回答