在 Code Igniter 中销毁特定会话

71

我希望能够在使用 Code Igniter 构建的应用程序中注销用户。

我知道如何结束当前活动的本地会话:

$this->session->sess_destroy();

如何销毁在另一台计算机上启动的会话,从而使用户退出其会话?

我将与其帐户相关联的唯一 ID 存储在会话数据中,因此我可以在数据库的会话表中查看它,但它与其他会话数据一起存储在名为 user_data 的列中,其内容类似于这样:

a:4:
{s:9:"user_data";s:0:"";s:6:"userid";s:6:"189034";s:9:"logged_in";b:1;s:5:"token";i:1767727789;}

其中189034是用户的ID。

那么,有没有一种方法可以根据用户的ID选择会话表中的行,然后删除该行并销毁会话。或者完全有其他方法来完成这个任务?

3个回答

41
在ci_session表中创建一个新列。
ALTER TABLE `yourdatabase`.`ci_sessions` 
ADD COLUMN `userid` VARCHAR(45) NULL  AFTER `user_data` ;

然后在您的登录函数中,从您的登录过程中获取 ID,在将用户数据信息添加到会话之前执行以下操作:

/* Delete any existing sessions with the current userid session.
Note - a new session has already been generated but doesn't have a value
in the userid column, so won't get deleted. */
$this->db->delete('ci_sessions',array('userid' => $identity));    

// Get the current session and update it with the userid value.
$session_id = $this->session->userdata('session_id');
$this->db->where('session_id', $session_id);
$this->db->update('ci_sessions', array('userid' => $identity));

其中$identity是您的用户ID。这将清除任何先前的会话,并意味着同时只存在一个会话。


当会话ID重新生成时,您不会丢失userid值吗?我记得这是我们在评论中讨论的问题。 - Wesley Murch
1
不。当用户从第二台机器登录但在用户被认证之前,会创建一个新的会话,因此此时数据库中有两条记录。使用上述代码,旧的会话记录将被销毁,新的记录将仅更新会话信息。我已经编辑了答案以使其更清晰。 - Stevo
1
我的意思是当同一个会话重新生成自己的id时。"...session类将检查用户会话cookie中是否存在有效的会话数据...如果会话存在,则其信息将被更新...每次更新时,session_id都将被重新生成。" 我有遗漏什么吗? - Wesley Murch
1
关键词是“更新”。数据库表中的元组(记录)被更新,而不是删除和插入。即由CodeIgniter运行的SQL代码为“update ci_sessions set session_id ='456def' where session_id ='abc123'”。因此,可以在会话存在期间维护userid列的完整性。 - Stevo
如果您使用的是C3,则应该使用以下查询语句: ALTER TABLE yourdatabase.ci_sessions ADD COLUMN userid VARCHAR(45) NULL AFTER data ; - Marcelo Agimóvel

5

这里有一个可以销毁你想要的一些项目/会话的功能。

$this->session->unset_userdata('session_name')

为了让一个用户一次只能在一台计算机或一个浏览器中登录,您可以在此处阅读更多信息。

一次只允许一个会话


4

序列化数据的一个问题是没有合法的查询方式。您需要获取会话中的所有用户(可能有很多),解包数据,检查值,然后删除会话表中的行,从而销毁该会话。

foreach ($this->db->get('sessions')->result() as $session)
{
    $data = unserialize($session->user_data);

    if ( ! isset($data['user_id'])) continue;

    if ($data['user_id'] === $id_to_delete)
    {
        // delete the row
            $this->db->where('session_id', $session->session_id)
                ->delete('sessions');
    }
}

我认为这种做法可能不太可行。您网站上的每个用户,无论是否登录,都有一个会话,这些会话需要逐一检查,而且还要记住:一个用户可能有多个会话,所以您需要逐个循环检查每个会话。
另一种方法是,在会话表中添加一个自定义列,其中包含用户ID(或ID的哈希值)。您可以通过查询该列来快速找到用户的会话。然后,在将user_id添加到会话时,填充此列。当您需要按user_id删除会话时,可以快速、高效地完成。

我也会不鼓励这种方法。你的第二个建议更现实。 - Stevo
虽然最简单的方法是添加此函数,但如果您有巨大的会话表,则不一定是最好的选择。 - user767124

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接