我想预防PHP应用程序中的多个登录。

首先,我在用户表中创建登录状态(活动,不活动)。

当用户a在用户状态中的日志时,将设置为“活动”,如果用户登录状态将设置为“ notactive”。当另一个客户使用相同的用户Acount登录时,我会检查用户表。如果用户仍处于活动状态,则错误登录将发送给用户。

问题发生了,如果用户关闭浏览器,则可以更新用户表中的状态,因为用户没有单击注销。

您对此有任何建议吗?

有帮助吗?

解决方案

(请注意,虽然这里的技术仍然有些有效; PHP样本不应逐字复制,因为在SQL查询中有更安全的方法将用户支持的值合并到SQL查询中)


与其存储用户是否处于活动状态 intactive,不如存储一些可以按照用户对用户进行检查的属性。就像在用户尝试执行需要身份验证的某些事情时,它将检查以查看此属性在进行之前是否匹配。

我建议您做以下操作;

首先,创建一个hash,每当用户登录时唯一识别。我想 sha1time() 足以避免发生冲突。无论您选择哪种选择,请确保它的变化足够多,以使其他用户登录的机会极低的机会接收相同的哈希(例如,不要哈希IP地址或浏览器的用户代理,因为这些都不会有变化足够的)。

其次,将此哈希存储在您的数据库和用户的 会议 在登录时。这样做将有效地“注销”以前的用户,因为每次登录时,哈希都应该有所不同。

由于我们正在使用会话,因此应在用户的浏览器中自动放置一个cookie,该浏览器将包含一个唯一的ID,该ID将用户标识为其会话数据。饼干的内容并不是真正令人关注的。

接下来,创建一个称为的函数 authenticateUser() 或类似的,将在每个脚本的开头调用,以确保用户得到身份验证。该脚本应查询数据库,检查以查看用户ID的用户是否具有与用户哈希相匹配的哈希。

例如:

function authenticateUser($id, $hash, $databaseLink) {
    # SQL
    $sql = 'SELECT EXISTS(
               SELECT 1
               FROM `tbl_users`
               WHERE `id` = \''.mysql_real_escape_string($id).'\'
               AND `hash` = \''.mysql_real_escape_string($hash).'\'
               LIMIT 1
           );';

    # Run Query
    if ($query = mysql_query($sql, $databaseLink)) {
        # Get the first row of the results
        # Assuming 'id' is your primary key, there
        # should only ever be one row anyway.       
        $result = mysql_fetch_row($query);

        # Casting to boolean isn't strictly necessary here
        # its included to indicate the mysql result should
        # only ever been 1 or 0.
        return (bool)($result[0]);
    } else {
        # Query error :(
        return false;
    }
}

然后,我们只是通过 authenticateUser() 用户的 ID, hash (根据您的会话数据)和 database link (对于数据库连接,您必须之前打开)。

如果 authenticateUser() 返回 true, ,用户已进行身份验证。如果 false, ,用户不是或数据库不可用或存在SQL错误。

但是请注意,这将增加您的服务器加载,因为每页请求一次发送数据库请求。在任何给定时间都在登录的巨型项目上,做到这一点可能并不明智。我敢肯定有人可以建议改进。

另外,等待饼干到期并不是强迫那些不活跃的人注销的人的最佳方法,因为您永远不应该相信cookie。相反,您可以添加一个名为的列 last_active 您可以每次对用户进行身份验证时进行更新。这也将增加服务器的负载,但可以通过删除来覆盖陈旧的日志 hash 对于那些无活动3个小时的用户。

其他提示

这是一个解决方案 需要恒定 数据库访问 去工作...

(这将避免每次请求/刷新页面,减轻DB/Server Present时,都需要检查Session_ID()()的要求)...

1. 在登录时,请抓住该用户DB中存储的预先存在的session_id,并执行此操作:

session_id("the pre-existing session id in the database goes here");
session_start();
session_destroy();

2. 然后启动一个新的会话,然后将此新的Session_ID保存到数据库中,覆盖上一个。如果有一个活动(使用此帐户有效记录另一个人),则将在此用户上注销上一个会话。

试试看,让我知道是否能解决问题!!

您可以更改模型,以便只能登录最新的用户。

如果您记录每个用户看到的最新会话ID,则第二次登录时,您可以将任何当前现有的会话丢弃,从而有效记录它们。

对于普通用户,事情似乎“只是工作”。如果您想防止“异常”用户分发其登录凭据,则应将其作为一种抑制作用。

您应该做的是检查他们在尝试登录时是否活跃了几分钟。这可以使用LastOnline邮票完成,应在用户表中的每个页面请求中设置。

如果未完成JavaScript,则可以在登录时检查,如果用户在最后15分钟内处于活动状态。如果不是,您可以登录新用户。

您也可以使用JavaScript做到这一点。打一个每分钟左右开火的Ajax电话。

<script>
setInterval(function() {
  // do the ajax call
}, 60000);
</script>

让此调用转到将编辑用户数据库中的LastOnline邮票的脚本。尝试登录时,如果LastOnline邮票超过了分钟,则检查用户数据库,如果您可以登录,则可以进行检查。当您在页面上时,这将有所帮助,但是您在最后15分钟内没有活跃,并且您不希望其他人登录。

您需要创建一个唯一的ID并将其存储在数据库中。我所做的也是创造。我将一个存储在会话变量中,并使用它来防止会话劫持,而另一个则在数据库中防止多个登录。以下代码将创建一个唯一的ID:

$unique_id = sha1('xzr4'.gethostbyaddr($_SERVER['REMOTE_ADDR']).$random_string.$_SERVER['HTTP_USER_AGENT'].'f8k2');

如果唯一的ID不匹配,则只需将用户记录出。

使用客户端JavaScript为了跟踪已登录的用户是不可靠的。

您可以通过简单地在DB中创建最后一个斑点字段来获得相同的结果,并使用用户的最后登录时间戳对其进行更新。

在每次登录尝试时,如果现在() - $ lastLogindate> predefined_timeout,则应接受新的登录名,否则拒绝它。

该解决方案类似于Prograhammer的解决方案,但您不需要您在切换会话方面弄乱。它不需要您在每个页面上访问数据库,并且在用户未能注销后不会锁定。

将sessionID的字段添加到数据库中的用户表中。

在调用session_start()之前设置默认的会话处理程序(下一行代码工作需要):

session_set_save_handler(new \SessionHandler());

在每个成功的登录名中,从数据库中检索存储的$ SessionID。销毁旧会议:

(new \SessionHandler())->destroy($sessionID);

获取新的会话ID:

$sessionID = session_id();

将新的会话ID存储到数据库中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top