使用Curl登录Laravel应用时出现"Page expired"报错求助
解决Laravel Curl登录返回「Page expired」的问题
嘿,别慌!作为Laravel开发者,这个「Page expired」提示太眼熟了——这是Laravel的CSRF令牌验证机制在起作用。你当前的curl脚本只提交了用户名和密码,但完全没处理Laravel要求的CSRF令牌,所以服务器直接拒绝了你的POST请求。
下面一步步帮你修复这个问题:
1. 先理解问题根源
Laravel默认会对所有web路由下的POST请求做CSRF保护,目的是防止跨站请求伪造。登录页面属于web路由,所以你必须在POST请求中带上页面生成的CSRF令牌,而且这个令牌和用户会话绑定,得先通过GET请求获取登录页面,拿到令牌同时保存会话Cookie。
2. 修正后的完整Curl脚本
<?php // 第一步:GET请求登录页面,获取CSRF令牌并保存Cookie $loginUrl = 'http://a.localhost/login'; $cookieFile = tempnam(sys_get_temp_dir(), 'laravel_cookie'); // 临时Cookie文件 // 初始化curl获取登录页面 $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $loginUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_COOKIEJAR => $cookieFile, // 保存Cookie到文件 ]); $loginPage = curl_exec($ch); curl_close($ch); // 从登录页面提取CSRF令牌(匹配meta标签里的内容) preg_match('/<meta name="csrf-token" content="(.*?)">/', $loginPage, $matches); if (!isset($matches[1])) { die('无法获取CSRF令牌'); } $csrfToken = $matches[1]; // 第二步:携带令牌和登录参数发起POST请求 $postData = [ '_token' => $csrfToken, // 必须带上的CSRF令牌字段 'name' => 'postmanole', 'password' => 'password' ]; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $loginUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($postData), // 把数组转成URL编码的表单数据 CURLOPT_COOKIEFILE => $cookieFile, // 读取之前保存的Cookie,维持会话 ]); $output = curl_exec($ch); // 检查请求是否成功 if (curl_errno($ch)) { echo 'Curl错误: ' . curl_error($ch); } else { echo $output; } curl_close($ch); // 清理临时Cookie文件 unlink($cookieFile); ?>
关键细节说明
- Cookie处理:用
CURLOPT_COOKIEJAR和CURLOPT_COOKIEFILE来维持会话,因为CSRF令牌和会话绑定,必须保证两次请求(GET和POST)用同一个会话。 - CSRF令牌提取:这里用正则匹配页面中的
<meta name="csrf-token">标签,你也可以匹配登录表单里的<input type="hidden" name="_token">字段,效果是一样的。 - POST数据格式:用
http_build_query()把数组转成标准的表单编码格式,符合Laravel的表单请求预期。
额外提示
如果你的登录接口是API路由(放在routes/api.php里),可以在app/Http/Middleware/VerifyCsrfToken.php里把登录路由加入$except数组,跳过CSRF验证,但这只适合纯API场景,普通web登录还是建议按上面的方法处理CSRF令牌。
内容的提问来源于stack exchange,提问作者Jesus
相关产品推荐
相关产品推荐

