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

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. 测试验证流程

  1. 访问https://mydomain.com/login完成登录,会自动跳转到another-domain.net/sync-session完成会话同步,随后回到原页面。
  2. 直接访问https://another-domain.net,检查是否已处于登录状态。
  3. 反向在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:01:00