CodeIgniter修改员工密码后销毁会话及会话存储路径选择咨询
嘿,作为经常和CodeIgniter打交道的开发者,我来给你梳理下这个需求的实现思路,其实分两步走:选对会话存储方式,再实现强制退出的逻辑,不难搞定!
一、先选对会话存储类型
首先,要实现“主动销毁指定用户会话”的需求,文件存储绝对是下下策——因为你得遍历服务器上所有会话文件,逐个解析内容找对应用户ID,效率低还容易出错,多服务器部署的话更没法玩。
推荐两种方案:
- 数据库存储:适合中小项目,配置简单,能直接关联用户ID,方便后续批量删除会话。
- Redis存储:适合高并发/多服务器项目,性能更强,销毁会话的操作更高效。
我先重点讲数据库存储的配置,这是最常用的:
数据库存储配置步骤
- 先创建会话表(以MySQL为例),可以加个
user_id字段关联你的用户表,方便后续查询:
CREATE TABLE IF NOT EXISTS `ci_sessions` ( `id` varchar(128) NOT NULL, `ip_address` varchar(45) NOT NULL, `timestamp` int(10) unsigned DEFAULT 0 NOT NULL, `data` blob NOT NULL, `user_id` int(11) DEFAULT NULL, -- 关联用户表的ID字段 PRIMARY KEY (id), KEY `ci_sessions_timestamp` (`timestamp`), KEY `ci_sessions_user_id` (`user_id`) -- 加索引提升查询速度 );
- 修改
application/config/config.php里的会话配置:
$config['sess_driver'] = 'database'; $config['sess_cookie_name'] = 'ci_session'; $config['sess_expiration'] = 7200; // 会话过期时间,按需调整 $config['sess_save_path'] = 'ci_sessions'; // 这里填你刚才创建的表名 $config['sess_match_ip'] = FALSE; // 若需要严格绑定IP可设为TRUE $config['sess_time_to_update'] = 300; $config['sess_regenerate_destroy'] = TRUE;
- 把用户ID绑定到会话记录:
CodeIgniter默认不会把user_id存入会话表的单独字段,所以我们可以用钩子来实现。在application/config/hooks.php添加:
$hook['post_controller_constructor'][] = array( 'class' => 'SessionHook', 'function' => 'update_user_id', 'filename' => 'SessionHook.php', 'filepath' => 'hooks' );
然后在application/hooks/SessionHook.php写钩子逻辑:
class SessionHook { public function update_user_id() { $CI =& get_instance(); // 如果用户已登录,把user_id写入当前会话记录 if ($CI->session->userdata('user_id')) { $session_id = $CI->session->session_id; $user_id = $CI->session->userdata('user_id'); $CI->db->where('id', $session_id)->update('ci_sessions', ['user_id' => $user_id]); } } }
二、实现密码修改后强制员工退出的逻辑
这里有两种可靠的实现方式,你可以根据需求选:
方式一:密码修改时间戳校验(推荐,覆盖多设备场景)
这个方法不需要直接操作会话,而是通过对比会话和数据库里的密码修改时间,来判断是否强制退出,能覆盖用户在多个设备登录的场景。
- 先在用户表加个
last_password_change字段(int类型,存时间戳),记录最后一次修改密码的时间。 - 用户登录时,把这个时间戳存入会话:
// 登录逻辑里,验证用户后 $user = $this->db->where('email', $email)->get('users')->row(); $this->session->set_userdata([ 'user_id' => $user->id, 'role' => $user->role, 'last_password_change' => $user->last_password_change ]);
- 管理员/经理修改员工密码时,更新密码和
last_password_change:
public function change_employee_password() { // 先做权限校验:只有admin或manager能执行 $current_role = $this->session->userdata('role'); if (!in_array($current_role, ['admin', 'manager'])) { show_error('无权限执行此操作', 403); } $employee_id = $this->input->post('employee_id'); $new_password = password_hash($this->input->post('new_password'), PASSWORD_DEFAULT); // 更新密码和修改时间 $this->db->where('id', $employee_id)->update('users', [ 'password' => $new_password, 'last_password_change' => time() ]); }
- 全局会话校验:在所有需要登录的控制器构造方法里,加入检查逻辑(或者写个基类控制器,让其他控制器继承):
class AdminBaseController extends CI_Controller { public function __construct() { parent::__construct(); $this->validate_session(); } private function validate_session() { // 未登录则跳转登录页 if (!$this->session->userdata('user_id')) { redirect('auth/login'); } // 对比会话和数据库的密码修改时间 $user = $this->db->where('id', $this->session->userdata('user_id'))->get('users')->row(); if ($user->last_password_change > $this->session->userdata('last_password_change')) { // 密码已被修改,销毁会话并跳转登录页 $this->session->sess_destroy(); redirect('auth/login?msg=password_updated_please_re_login'); } } }
方式二:直接删除用户所有会话记录
如果需要立即让用户退出,也可以在修改密码后直接删除该用户的所有会话记录:
// 修改密码后执行 $this->db->where('user_id', $employee_id)->delete('ci_sessions');
这个方法会立即销毁该用户的所有会话,但如果用户刚发起请求,可能新的会话已经创建,不过大部分场景下都能生效。
三、额外注意事项
- 权限控制一定要做严:确保只有admin和manager能访问修改员工密码的接口,避免越权操作。
- 密码加密必须用
password_hash(),千万不要用明文或者MD5这类弱加密方式。 - 如果用Redis存储,配置逻辑类似,只需要把
sess_driver设为'redis',sess_save_path设为'tcp://127.0.0.1:6379'(你的Redis地址),然后同样可以通过Redis的命令删除指定用户的会话。
内容的提问来源于stack exchange,提问作者Tamilselvan S
相关产品推荐
相关产品推荐

