ThinkPHP 6 跨域共享 Session 必须统一使用 redis 或 database 驱动,禁用 file 和 memcached;子域名需设 session.cookie_domain 为 .example.com 并确保 PHP 和 Nginx 配置生效;跨主域需透传并校验 session_id;所有应用必须统一 session.prefix。

ThinkPHP 6 的 session_driver 配置必须统一为 redis 或 database
文件型 session(file)在多域名下天然无法共享,因为每个应用写入的是各自服务器本地路径,且 PHP 默认用 phpsessid + 域名 Cookie 作用域隔离。强行改 session.cookie_domain 也无效——不同主域(如 a.com 和 b.com)浏览器根本不允许共享 Cookie。
所以第一步不是调 Cookie,而是换驱动:
-
redis最常用:所有应用连同一个 Redis 实例,session_id作为 key 写入,天然跨应用可见 -
database也可行:共用一张session表,注意session_table名和连接配置一致 - 别碰
memcached:TP6 官方驱动对 Memcached 的过期策略处理不稳,容易出现“明明没过期却读不到”
多个子域名(如 admin.example.com 和 api.example.com)要设 session.cookie_domain 为 .example.com
这是唯一能绕过浏览器同源限制的合法方式——前提是所有域名属于同一主域。注意点很具体:
- 必须带开头的点号:
.example.com,写成example.com或www.example.com都无效 - ThinkPHP 中不能只在
config/session.php改,还要确保底层 PHP 设置生效:ini_set('session.cookie_domain', '.example.com');要在 session 启动前执行 - 如果用了 Nginx,检查是否加了
proxy_cookie_domain ~^(.+)$ .example.com;,否则反向代理会覆盖原始 Cookie 域名
跨主域(如 a.com 和 b.net)只能靠后端透传 session_id,不能依赖 Cookie
浏览器规则不可绕过。这时候得放弃“自动携带”,改用显式传递:
立即学习“PHP免费学习笔记(深入)”;
- 前端发起请求时,把当前
session_id()作为 URL 参数或 Header(如X-Session-ID)带上 - 接收方应用在
session_start()前,先从请求中提取该 ID,再调用session_id($id)强制指定 - 务必校验该
session_id是否真实存在且未过期(比如查 Redis 的exists),否则可能被伪造 - TP6 的
think\facade\Session不支持运行时切换 ID,得直接操作原生 PHP session 函数
Redis 共享 Session 时,session_prefix 必须清空或保持一致
TP6 默认给所有 session key 加前缀 think_session:,这本身没问题。但如果你在不同应用里手动改过 session.prefix 配置项,比如一个写 app1:、另一个写 app2:,那它们根本读不到对方的 session 数据。
解决方法很简单:
- 所有应用的
config/session.php中,'prefix' => ''(空字符串)最安全 - 或者统一设成同一个值,比如
'prefix' => 'common:',但别用变量拼接 - Redis CLI 里用
keys *session*检查实际 key 名,确认是不是预期格式
跨域 Session 看似是 Cookie 问题,其实核心是存储层和 ID 生成逻辑的一致性。漏掉任何一个环节,比如 Redis 密码不一致、session.name 不同、甚至 PHP 版本对 session_encode 处理差异,都会导致“看起来登录了,但换个页面就掉线”。



















