Symfony 3.4单应用多域名会话共享实现方案问询
实现Symfony 3.4单应用多域名会话共享
针对你的场景——同一Symfony 3.4应用服务mydomain.com和another-domain.net两个域名,实现一次登录即可跨域名访问,我会分步骤给出具体落地方案:
1. 统一会话存储配置
默认文件会话存储在单服务器场景下是共享的,但为了更可靠地跨域名同步会话(尤其是多服务器部署场景),建议改用数据库或Redis存储。这里以数据库存储为例:
调整framework.yml会话配置
打开app/config/framework.yml,修改会话相关参数:
framework: session: # 指定数据库会话处理器 handler_id: session.handler.pdo # 取消域名绑定,让Cookie适配当前请求的域名 cookie_domain: ~ # 自动适配HTTPS环境发送Cookie cookie_secure: auto # 设置Cookie有效期为1天(按需调整) cookie_lifetime: 86400 # 允许跨域名同步时的Cookie操作(可选,根据业务需求) cookie_http_only: false
配置PDO会话服务
在app/config/services.yml添加会话处理器服务:
services: session.handler.pdo: class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler arguments: - '%database_url%' - { lock_mode: 1 }
执行命令创建会话存储表:
php bin/console doctrine:schema:create --em=default --filter=Session
2. 修改Guard认证器,添加跨域会话同步
基于你现有的Guard认证器,我们需要在登录成功后,为另一个域名同步会话状态。核心思路是:登录完成后重定向到目标域名的专用路由,传递加密后的会话标识,完成Cookie同步。
2.1 添加跨域会话同步路由
在app/config/routing.yml新增路由:
sync_session: path: /sync-session defaults: { _controller: AppBundle:Session:sync }
2.2 编写会话同步控制器
// src/AppBundle/Controller/SessionController.php namespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class SessionController extends Controller { public function syncAction(Request $request) { // 验证请求来源,仅允许可信域名访问 $allowedDomains = ['mydomain.com', 'another-domain.net']; $refererDomain = parse_url($request->headers->get('Referer'), PHP_URL_HOST); if (!in_array($refererDomain, $allowedDomains)) { return new Response('Invalid request', Response::HTTP_FORBIDDEN); } // 获取加密后的会话ID(示例简化,实际需用JWT等方式加密) $sessionId = $request->query->get('sid'); if (!$sessionId) { return new Response('Missing session ID', Response::HTTP_BAD_REQUEST); } // 加载目标会话并同步认证状态 $session = $this->get('session'); $session->setId($sessionId); $session->start(); $token = $this->get(TokenStorageInterface::class)->getToken(); if ($token) { $session->set('_security_main', serialize($token)); } // 重定向回原请求页面 return $this->redirect($request->query->get('redirect', '/')); } }
2.3 更新Guard认证器的登录成功逻辑
修改你现有Guard认证器的onAuthenticationSuccess方法,添加跨域同步重定向:
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { // 确定当前域名和目标同步域名 $currentDomain = $request->getHost(); $targetDomain = $currentDomain === 'mydomain.com' ? 'another-domain.net' : 'mydomain.com'; // 获取当前会话ID(实际需加密后传递) $sessionId = $request->getSession()->getId(); $syncUrl = sprintf('https://%s/sync-session?sid=%s&redirect=%s', $targetDomain, urlencode($sessionId), urlencode($request->getUri()) ); // 先同步目标域名会话,再返回原页面 return new RedirectResponse($syncUrl); }
3. 测试验证流程
- 访问
https://mydomain.com/login完成登录,会自动跳转到another-domain.net/sync-session完成会话同步,随后回到原页面。 - 直接访问
https://another-domain.net,检查是否已处于登录状态。 - 反向在
another-domain.net登录,验证mydomain.com是否同步保持登录。
关键注意事项
- 安全加固:示例中直接传递会话ID存在风险,建议用JWT对会话ID签名加密,同步路由验证签名后再加载会话。
- 强制HTTPS:务必使用HTTPS协议,避免Cookie被拦截窃取。
- 子域名简化方案:如果你的两个域名是同一顶级域名的子域名(如
a.mydomain.com和b.mydomain.com),可直接设置cookie_domain: .mydomain.com,无需额外同步逻辑,浏览器会自动共享Cookie。
内容的提问来源于stack exchange,提问作者Alex Rock
相关产品推荐
相关产品推荐

