You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PHP和Ajax实现登录表单“记住我”功能的页面刷新问题排查

解决“记住我”功能无法持久化登录状态的问题

我看了你的代码,发现几个核心问题导致“记住我”功能不生效,而且还有严重的安全隐患,咱们一步步来修复:

一、首要安全问题:绝对不要在Cookie中存储明文密码

你现在直接把用户的明文密码存在Cookie里,这是非常危险的——任何人只要拿到这个Cookie就能冒充用户登录。正确的做法是生成一个唯一、不可预测的令牌(token),同时存在数据库和Cookie中,完全避开存储密码的操作。

二、逻辑缺陷:勾选“记住我”时未初始化Session,且入口页未处理Cookie自动登录

当前代码里,当用户勾选“记住我”时,你只设置了Cookie但没有创建Session,而跳转后的patient-details.php大概率依赖Session判断登录状态。另外,登录入口页只检查了Session或Cookie的存在,但没有在Cookie有效时自动完成登录流程,导致Cookie存在也无法直接进入系统。

三、Cookie路径问题

setcookie的第四个参数(路径)你传的是空字符串,这会导致Cookie只在当前目录有效,如果你的登录页在子目录,跳转后可能无法读取到Cookie。建议设置为"/",让全站都能访问。


修改后的代码示例

1. 数据库新增字段(用于存储记住我令牌)

先给tbl_patients表新增两个字段:

  • remember_token:字符串类型,长度建议64,用于存储唯一令牌
  • remember_token_expiry:datetime类型,存储令牌过期时间

2. 登录页(HTML)

新增Cookie自动登录逻辑,确保用户下次访问时能直接通过Cookie验证:

<!DOCTYPE html> 
<?php 
session_start(); 
// 新增:如果存在有效的记住我Cookie,自动完成登录
if(isset($_COOKIE['remember_token'])){
    $conn = new mysqli("localhost", "root", "", "mydb") or die(mysqli_error());
    $token = mysqli_real_escape_string($conn, $_COOKIE['remember_token']);
    $sql = "SELECT * FROM tbl_patients WHERE remember_token = '$token' AND remember_token_expiry > NOW()";
    $result = mysqli_query($conn, $sql);
    if(mysqli_num_rows($result) == 1){
        $row = mysqli_fetch_assoc($result);
        $_SESSION['patient_id'] = $row['patient_id'];
        $_SESSION['username'] = $row['username'];
        header('location: patient-details.php');
        exit;
    }
}
// 原有登录状态检查
if( isset($_SESSION['patient_id']) ) { 
    header('location: patient-details.php'); 
    exit;
} 
?> 
<html lang="en"> 
<head> 
</head> 
<body class="bg-gradient-primary"> 
<div class="container"> 
<!-- Outer Row --> 
<div class="row justify-content-center"> 
<div class="col-xl-5 col-lg-3 col-md-3"> 
<div class="card o-hidden border-0 shadow-lg my-5"> 
<div class="card-body p-0"> 
<!-- Nested Row within Card Body --> 
<div class="row"> 
<div class="col-lg-12"> 
<div class="p-5"> 
<div class="text-center"> 
<h1 class="h4 text-gray-900 mb-4">Kabi Medical Records</h1> 
<h7 class="h7 text-gray-900 mb-4">Log in to continue.</h7> 
</div> 
<form class="user" method = "POST" id="loginform"> 
<hr> 
<div id="loginmessage"></div> 
<div class="form-group"> 
<input type="text" class="form-control form-control-user" id="UserName" aria-describedby="username" placeholder="User Name" name="username" value=""> 
</div> 
<div class="form-group"> 
<input type="password" class="form-control form-control-user" id="UserPassword" placeholder="Password" name="password" value=""> 
</div> 
<div class="form-group"> 
<div class="custom-control custom-checkbox small"> 
<input type="checkbox" class="custom-control-input" id="customCheck" name="remember" value="yes"> 
<label class="custom-control-label" for="customCheck">Remember Me</label> 
</div> 
</div> 
<button type="submit" id="userloginbtn" class="btn btn-primary btn-user btn-block" name="login">Login</button> 
</form> 
<hr> 
<div class="text-center"> 
<a class="small" href="#">Forgot Password?</a> 
</div> 
<div class="text-center"> 
<a class="small" href="/kabirecords">Back to Home</a> 
</div> 
</div> 
</div> 
</div> 
</div> 
</div> 
</div> 
</div> 
</div> 
<script src="vendor/jquery/jquery.min.js"></script> 
<script src="assets/js/l.js"></script> 
</body> 
</html>

3. Login.php(处理登录请求)

修改Cookie逻辑为令牌模式,同时确保无论是否勾选“记住我”都初始化Session:

<?php 
//Start session 
session_start(); 
//Connect to the database 
$conn = new mysqli("localhost", "root", "", "mydb") or die(mysqli_error()); 
// 防止SQL注入,转义用户输入
$username = mysqli_real_escape_string($conn, trim($_POST['username'])); 
$password = mysqli_real_escape_string($conn, trim($_POST['password'])); 
$remember = isset($_POST['remember']) ? $_POST['remember'] : "no"; 

//Run query: Check combinaton of username & password exists 
$sql = "SELECT * FROM tbl_patients WHERE username='$username' && password='$password'"; 
$result = mysqli_query($conn, $sql) or die(mysqli_error()); 

if(!empty($username) && !empty($password)) { 
    $count = mysqli_num_rows($result); 
    if ($count !== 1) { 
        echo '<div class="alert alert-danger">Wrong Username or Password</div>'; 
    } else { 
        $row = mysqli_fetch_array($result, MYSQLI_ASSOC); 
        // 不管是否记住我,都初始化Session保证当前登录有效
        $_SESSION['patient_id'] = $row['patient_id']; 
        $_SESSION['username'] = $row['username']; 

        if($remember == "yes") { 
            // 生成32字节的随机令牌,转为16进制字符串
            $token = bin2hex(random_bytes(32)); 
            $expiry = date('Y-m-d H:i:s', time() + (60*60*24*7)); // 7天后过期
            // 更新数据库中的令牌和过期时间
            $update_sql = "UPDATE tbl_patients SET remember_token = '$token', remember_token_expiry = '$expiry' WHERE patient_id = " . $row['patient_id'];
            mysqli_query($conn, $update_sql);
            // 设置Cookie,路径为"/"确保全站可访问
            setcookie('remember_token', $token, time()+(60*60*24*7), "/"); 
        } else { 
            // 如果不勾选,清除可能存在的记住我Cookie
            if(isset($_COOKIE['remember_token'])){
                setcookie('remember_token', "", time()-3600, "/");
                // 同时清空数据库中的令牌
                $update_sql = "UPDATE tbl_patients SET remember_token = NULL, remember_token_expiry = NULL WHERE patient_id = " . $row['patient_id'];
                mysqli_query($conn, $update_sql);
            }
        } 
        echo "success"; 
    } 
} else { 
    echo '<div class="alert alert-danger">Both are Required Fields </div>'; 
} 
?>

4. Login.js(保持原有逻辑,无需修改)

$("#loginform").submit(function(event) { 
    //prevent default php processing 
    event.preventDefault(); 
    //collect user inputs 
    var datatopost = $(this).serializeArray(); 
    //send them to login.php using AJAX 
    $.ajax({ 
        url: "login.php", 
        type: "POST", 
        data: datatopost, 
        success: function(data) { 
            if ($.trim(data) === "success") { 
                Swal.fire({ 
                    icon: 'success', 
                    title: 'Login successful', 
                }); 
                window.location = "patient-details.php"; 
            } else { 
                $("#loginmessage").html(data); 
            } 
        }, 
        error: function() { 
            $("#loginmessage").html( "<div class='alert alert-danger'>There was an error with the Ajax Call. Please try again later.</div>" ); 
        } 
    }); 
}); 

额外优化建议

  • 密码存储优化:现在你直接存储明文密码在数据库里,这也是严重的安全问题,建议使用password_hash()加密密码,用password_verify()验证密码。
  • SQL注入防护:我在代码里加了mysqli_real_escape_string(),但更推荐使用预处理语句(Prepared Statements)来彻底防止SQL注入。
  • Cookie安全属性:可以给setcookie添加httponly和secure属性,增强安全性:setcookie('remember_token', $token, time()+(60*60*24*7), "/", "", true, true);(secure需要HTTPS环境)。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:56:09