干净的方法是将用户的姓名/数据保存在一个监听security.interactive_logout 事件的EventSubscriber/Listener 中的会话中。
由此产生的两个问题是:
- 默认
LogoutHandler没有调度注销事件
- symfony 根据默认配置在注销时清除会话
您可以通过将invalidate_session 设置为false 来更改会话清除行为
security:
firewalls:
main:
# [..]
logout:
path: 'fos_user_security_logout'
target: '/logoutpage'
invalidate_session: false # <- do not clear the session
handlers:
- 'Namespace\Bridge\Symfony\Security\Handler\DispatchingLogoutHandler'
对于注销事件,您可以像这样创建注销处理程序:
class DispatchingLogoutHandler implements LogoutHandlerInterface
{
/** @var EventDispatcherInterface */
protected $eventDispatcher;
/**
* @param EventDispatcherInterface $event_dispatcher
*/
public function __construct(EventDispatcherInterface $event_dispatcher)
{
$this->eventDispatcher = $event_dispatcher;
}
/**
* {@inheritdoc}
*/
public function logout(Request $request, Response $response, TokenInterface $token)
{
$this->eventDispatcher->dispatch(
SecurityExtraEvents::INTERACTIVE_LOGOUT,
new InteractiveLogoutEvent($request, $response, $token)
);
}
}
添加一些服务配置(或使用自动装配):
Namespace\Bridge\Symfony\Security\Handler\DispatchingLogoutHandler:
class: 'Namespace\Bridge\Symfony\Security\Handler\DispatchingLogoutHandler'
arguments:
- '@event_dispatcher'
事件类
namespace Namespace\Bridge\Symfony;
final class SecurityExtraEvents
{
/**
* @Event("\Namespace\Bridge\Symfony\Security\Event\Logout\InteractiveLogoutEvent")
*/
const INTERACTIVE_LOGOUT = 'security.interactive_logout';
}
事件本身:
final class InteractiveLogoutEvent extends Event
{
/**
* @var Request
*/
protected $request;
/**
* @var Response
*/
protected $response;
/**
* @var TokenInterface
*/
protected $token;
/**
* @param Request $request
* @param Response $response
* @param TokenInterface $token
*/
public function __construct(Request $request, Response $response, TokenInterface $token)
{
$this->request = $request;
$this->response = $response;
$this->token = $token;
}
/**
* @return TokenInterface
*/
public function getToken()
{
return $this->token;
}
/**
* @return TokenInterface
*/
public function getRequest()
{
return $this->token;
}
/**
* @return Response
*/
public function getResponse()
{
return $this->response;
}
/**
* @return string
*/
public function getName()
{
return SecurityExtraEvents::INTERACTIVE_LOGOUT;
}
}
订阅者:
class UserEventSubscriber implements EventSubscriberInterface
{
/** @var LoggerInterface */
protected $logger;
/** @param LoggerInterface $logger */
public function __construct(LoggerInterface $logger)
{
// inject the session here
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
SecurityExtraEvents::INTERACTIVE_LOGOUT => 'onInteractiveLogout',
);
}
/**
* {@inheritdoc}
*/
public function onInteractiveLogout(InteractiveLogoutEvent $event)
{
$user = $event->getToken()->getUser();
// save the username in the session here
$this->logger->info(
'A User has logged out.',
array(
'event' => SecurityExtraEvents::INTERACTIVE_LOGOUT,
'user' => array(
'id' => $user->getId(),
'email' => $user->getEmail(),
)
)
);
}
}
通过使用kernel.event_subscriber 标记订阅者来启用它
Namespace\EventSubscriber\UserEventSubscriber:
class: 'Namespace\EventSubscriber\UserEventSubscriber'
arguments: ['@monolog.logger.user']
tags:
- { name: 'kernel.event_subscriber' }
简单吧?一个有点脏的解决方案是创建一个请求侦听器,将用户名保存在每个请求的 session-flashbag 中,以便您可以从那里在注销页面模板中获取它。