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

PHP通过cURL实现SiteA至SiteB跨站登录后,跳转受限内容仍需登录的问题解决咨询

问题:通过PHP Curl调用CI4 API登录后,跳转SiteB受限页面却被导向登录页

我开发了一个PHP API函数,用于实现用户从SiteA登录至SiteB。SiteA端的siteA-login.php代码如下:

$url = "https://api.siteb.com/login";
$cookie = "cookie-api.txt";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
//curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, "data=".json_encode($curlPost));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($curl, CURLOPT_COOKIEJAR, $cookie);
curl_setopt ($curl, CURLOPT_COOKIEFILE, $cookie);
curl_setopt ($curl, CURLOPT_REFERER, $url);
$response = (curl_exec($curl));
curl_close($curl);
header("location: https://siteb.com/restricted-content");

SiteB端采用CodeIgniter4(CI4)框架处理用户登录,代码如下:

$session = session();
$session->set(array('user'=>$user));

然而执行跳转后,我并未进入受限内容页面,反而被导向登录页面,请问该如何解决此问题?


解决方案

问题根源分析

你遇到的核心问题是Cookie的存储隔离:

  • 你在SiteA服务器上用Curl发起的请求,对应的Cookie是存在SiteA服务器的cookie-api.txt文件里的,这属于服务器端的Cookie会话。
  • 当你通过header("location: ...")让用户浏览器跳转到SiteB时,浏览器并不会携带SiteA服务器上的这个Cookie,SiteB的CI4框架自然识别不到已登录的Session,所以会把你导向登录页。

接下来给你两种可行的解决思路:


方案1:传递Session ID到浏览器Cookie

让SiteB的登录API返回登录后的Session ID,然后SiteA把这个ID设置到用户浏览器的Cookie中(要匹配SiteB的Session Cookie配置),这样浏览器跳转时就能携带有效的Session信息。

步骤1:修改SiteB的CI4登录接口

处理完登录后,返回当前的Session ID:

// SiteB的登录API控制器方法
public function login() {
    // 这里省略验证用户账号密码的逻辑
    $user = $this->userModel->getUserByCredentials(...);
    
    $session = session();
    $session->set(array('user'=>$user));
    
    // 返回登录成功状态和Session ID
    return $this->response->setJSON([
        'status' => 'success',
        'session_id' => session_id()
    ]);
}

步骤2:修改SiteA的siteA-login.php

解析API返回的Session ID,然后设置对应SiteB的Cookie:

$url = "https://api.siteb.com/login";
$cookie = "cookie-api.txt";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_POSTFIELDS, "data=".json_encode($curlPost));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($curl, CURLOPT_COOKIEJAR, $cookie);
curl_setopt ($curl, CURLOPT_COOKIEFILE, $cookie);
curl_setopt ($curl, CURLOPT_REFERER, $url);
// 解析JSON格式的响应
$response = json_decode(curl_exec($curl), true);
curl_close($curl);

if (!empty($response['status']) && $response['status'] === 'success') {
    // 注意:这里的Cookie参数要和SiteB的CI4 Session配置一致
    // 假设SiteB的Session Cookie名是ci_session,域名是siteb.com,路径为根目录
    setcookie(
        'ci_session', 
        $response['session_id'], 
        0, // 有效期随浏览器关闭而失效
        '/', // Cookie生效路径
        'siteb.com', // 域名,必须和SiteB一致
        true, // 仅HTTPS下传输
        true // 禁止JS读取,提升安全性
    );
}

header("location: https://siteb.com/restricted-content");

注意:如果SiteA和SiteB是不同主域(比如sitea.com和siteb.com),这种跨域设置Cookie需要满足:SiteB的服务器配置了Access-Control-Allow-Credentials: true,且Cookie的SameSite属性设为None,同时必须使用HTTPS协议。


方案2:使用JWT令牌替代Session传递

如果跨域Cookie的配置太麻烦,推荐用JWT(JSON Web Token)来传递登录状态,这是跨域场景下更灵活的方案。

步骤1:在SiteB安装JWT依赖

首先通过Composer安装Firebase的JWT包:

composer require firebase/php-jwt

步骤2:修改SiteB的登录API生成JWT

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

public function login() {
    // 省略用户验证逻辑
    $user = $this->userModel->getUserByCredentials(...);
    
    // 定义JWT密钥(要保密,验证时要一致)
    $secretKey = 'your-strong-secret-key-here';
    // 构建JWT payload,包含用户信息和有效期
    $payload = [
        'iss' => 'https://siteb.com', // 签发者
        'exp' => time() + 3600, // 有效期1小时
        'user' => $user // 用户信息(建议只存必要字段,比如ID、用户名)
    ];
    
    // 生成JWT令牌
    $jwt = JWT::encode($payload, $secretKey, 'HS256');
    
    return $this->response->setJSON([
        'status' => 'success',
        'token' => $jwt
    ]);
}

步骤3:SiteA跳转时携带JWT令牌

// 前面的Curl代码和方案1一致
$response = json_decode(curl_exec($curl), true);
curl_close($curl);

if (!empty($response['status']) && $response['status'] === 'success') {
    // 跳转时把JWT作为URL参数传递(也可以设置到Cookie,根据需求选择)
    $redirectUrl = "https://siteb.com/restricted-content?token=" . urlencode($response['token']);
    header("location: " . $redirectUrl);
    exit;
}

// 如果登录失败,跳转到错误页或者SiteA的登录页
header("location: /login");

步骤4:SiteB的受限页面验证JWT

在SiteB的受限页面控制器中,先验证JWT令牌,通过后初始化Session:

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

public function restrictedContent() {
    $secretKey = 'your-strong-secret-key-here'; // 和生成JWT时的密钥一致
    $token = $this->request->getGet('token');
    
    if (empty($token)) {
        return redirect()->to('/login');
    }
    
    try {
        // 验证JWT令牌
        $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));
        // 初始化Session
        $session = session();
        $session->set(['user' => (array)$decoded->user]);
    } catch (\Exception $e) {
        // 验证失败,跳转登录页
        return redirect()->to('/login');
    }
    
    // 正常渲染受限内容视图
    return view('restricted-content');
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 22:07:29