You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

会话过期自动登出用户及记住我功能实现求助

嘿,我来帮你搞定这两个功能——会话过期自动登出和「记住我」复选框的正确实现。先看看你现有代码里的几个小问题,再一步步调整:

一、修复「记住我」复选框功能

你当前的代码存在几个关键问题:

  • 不管复选框是否勾选都会设置cookie,不符合“记住我”的触发逻辑
  • 直接把用户名存在cookie里,安全性极低,一旦cookie被盗,攻击者可直接冒充用户
  • cookie过期时间仅设置了5分钟(300秒),完全起不到“长期记住”的作用
  • 缺少安全属性,容易遭遇XSS、CSRF等攻击

以下是修改后的完整实现(假设你的用户表新增了remember_token字段,用于存储哈希后的令牌):

验证密码通过后的处理代码

if(password_verify($password, $hashed_password)){ 
    session_start(); 
    session_regenerate_id(true); // 重置session ID,防止会话固定攻击
    $_SESSION['username'] = $username; 
    $_SESSION['firstname'] = $firstname;
    $_SESSION['last_activity'] = time(); // 记录会话最后活动时间,用于自动登出

    // 仅当复选框被勾选时,才设置记住我cookie
    if(isset($_POST['remember_me']) && $_POST['remember_me'] === 'on'){
        // 生成32位随机安全令牌
        $rememberToken = bin2hex(random_bytes(32));
        // 哈希令牌后存入数据库(永远不要存明文令牌)
        $hashedToken = password_hash($rememberToken, PASSWORD_DEFAULT);
        
        // 更新用户表的remember_token字段(这里用PDO示例,可根据你的数据库连接方式调整)
        $stmt = $pdo->prepare("UPDATE users SET remember_token = ? WHERE username = ?");
        $stmt->execute([$hashedToken, $username]);

        // 设置cookie,过期时间为30天
        $cookieExpiry = time() + 30 * 24 * 60 * 60;
        setcookie(
            'remember_me',
            $username . '|' . $rememberToken, // 存储用户名+令牌,后续验证用
            $cookieExpiry,
            "/",
            NULL,
            true, // secure:仅HTTPS传输,HTTP环境可改为false
            true  // httponly:禁止JS读取,防范XSS攻击
        );
    } else {
        // 若未勾选,删除已存在的remember_me cookie
        setcookie('remember_me', '', time() - 3600, "/");
    }

    header("location: index.php");
    exit; // 跳转后必须exit,避免后续代码执行
}

复选框代码(补全缺失部分)

<label class="css-input switch switch-sm switch-primary">
    <input type="checkbox" name="remember_me" id="rememberMe">
    <span></span> 记住我
</label>
二、实现会话过期自动登出功能

需要在所有需要登录访问的页面顶部,添加会话过期检查逻辑(建议封装成单独的auth.php文件,通过include('auth.php')引入):

session_start();

// 设置会话过期时间,比如30分钟(1800秒),可按需调整
$sessionTimeout = 1800;

// 检查用户是否已登录
if(isset($_SESSION['username'])){
    // 检查会话是否过期
    if(isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > $sessionTimeout)){
        // 销毁会话,强制登出
        session_unset();
        session_destroy();
        header("location: login.php?expired=1");
        exit;
    }
    // 若会话有效,刷新最后活动时间
    $_SESSION['last_activity'] = time();
} else {
    // 未登录时,检查是否有remember_me cookie,实现自动登录(可选)
    if(isset($_COOKIE['remember_me'])){
        list($username, $rememberToken) = explode('|', $_COOKIE['remember_me'], 2);
        // 从数据库获取用户的哈希令牌
        $stmt = $pdo->prepare("SELECT remember_token, firstname FROM users WHERE username = ?");
        $stmt->execute([$username]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if($user && password_verify($rememberToken, $user['remember_token'])){
            // 令牌验证通过,重建会话
            session_regenerate_id(true);
            $_SESSION['username'] = $username;
            $_SESSION['firstname'] = $user['firstname'];
            $_SESSION['last_activity'] = time();
            // 可选:刷新cookie过期时间,延长记住我时长
            $cookieExpiry = time() + 30 * 24 * 60 * 60;
            setcookie(
                'remember_me',
                $username . '|' . $rememberToken,
                $cookieExpiry,
                "/",
                NULL,
                true,
                true
            );
        } else {
            // 令牌无效,删除恶意cookie
            setcookie('remember_me', '', time() - 3600, "/");
        }
    } else {
        // 未登录且无记住我cookie,跳转到登录页
        header("location: login.php");
        exit;
    }
}

额外注意事项

  • 所有数据库操作必须使用预处理语句(如PDO/mysqli预处理),防止SQL注入
  • 若网站使用HTTP协议,需将setcookie中的secure参数改为false,但建议尽快迁移到HTTPS
  • 会话过期时间可根据业务需求调整,比如设置为1小时(3600秒)

内容的提问来源于stack exchange,提问作者Alan Moe

火山引擎 最新活动