如何为Symfony配置两套不同的session存储以适配前后台需求
Symfony 4 LTS 双Session存储方案实现
你提出的配置双会话处理器的思路是完全可行的,不需要从零开发完整的自定义SessionHandler,只要增加一个代理分发层即可实现按访问场景分配存储介质的需求,具体实现步骤如下:
1. 配置基础会话处理器
先在config/packages/framework.yaml中声明你需要的两套原生处理器:
framework: session: handler_id: App\Session\DelegatingSessionHandler # 其他session基础配置(cookie有效期、名称等)照常编写即可 services: # 后台用默认文件存储处理器 session.handler.native_file: class: Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler arguments: ['%kernel.cache_dir%/sessions'] # 前台用数据库存储处理器,直接用Symfony自带的PDOSessionHandler session.handler.pdo: class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler arguments: $pdoOrDsn: '%env(DATABASE_URL)%' $options: db_table: 'sessions' db_id_col: 'session_id' db_data_col: 'session_data' db_time_col: 'session_lifetime'
2. 编写分发代理SessionHandler
自定义一个实现SessionHandlerInterface的代理类,根据当前请求的路由/防火墙动态选择调用对应的处理器:
<?php namespace App\Session; use Symfony\Component\HttpFoundation\RequestStack; use SessionHandlerInterface; class DelegatingSessionHandler implements SessionHandlerInterface { private $adminHandler; private $frontHandler; private $requestStack; public function __construct( SessionHandlerInterface $adminHandler, SessionHandlerInterface $frontHandler, RequestStack $requestStack ) { $this->adminHandler = $adminHandler; $this->frontHandler = $frontHandler; $this->requestStack = $requestStack; } private function getActiveHandler(): SessionHandlerInterface { $request = $this->requestStack->getCurrentRequest(); // 两种判断规则二选一即可: // 方案1:按路由前缀判断,例后台路由均以/admin开头 if ($request && strpos($request->getPathInfo(), '/admin') === 0) { return $this->adminHandler; } // 方案2:按防火墙名称判断,需要安装security-bundle // $firewallContext = $request->attributes->get('_firewall_context'); // $firewallName = $firewallContext ? explode('.', $firewallContext)[1] : null; // if ($firewallName === 'admin') { // return $this->adminHandler; // } return $this->frontHandler; } public function open($savePath, $sessionName): bool { return $this->getActiveHandler()->open($savePath, $sessionName); } public function close(): bool { return $this->getActiveHandler()->close(); } public function read($sessionId): string|false { return $this->getActiveHandler()->read($sessionId); } public function write($sessionId, $sessionData): bool { return $this->getActiveHandler()->write($sessionId, $sessionData); } public function destroy($sessionId): bool { return $this->getActiveHandler()->destroy($sessionId); } public function gc($maxLifetime): int|false { // 垃圾回收时同步清理两个存储的过期数据,避免冗余 return $this->adminHandler->gc($maxLifetime) + $this->frontHandler->gc($maxLifetime); } }
3. 绑定服务参数
在config/services.yaml中为代理类注入对应的处理器实例:
services: App\Session\DelegatingSessionHandler: arguments: $adminHandler: '@session.handler.native_file' $frontHandler: '@session.handler.pdo'
4. 初始化数据库存储表
如果使用MySQL作为前台session存储,执行建表语句即可:
CREATE TABLE `sessions` ( `session_id` VARCHAR(128) NOT NULL PRIMARY KEY, `session_data` BLOB NOT NULL, `session_lifetime` INTEGER UNSIGNED NOT NULL, `session_time` INTEGER UNSIGNED NOT NULL ) COLLATE utf8mb4_bin, ENGINE = InnoDB;
内容的提问来源于stack exchange,提问作者chaillouvincent
相关产品推荐
相关产品推荐

