如何在 FOSUserBundle 注销页面上获取用户详细信息?

How to get user details on FOSUserBundle logout page?

我在 Symfone 2.8 webapp 项目中使用 FOSUserBundle。目前,用户在注销时被简单地重定向到主页。这应该更改为 "personal" 可以(可选)显示个人信息的注销页面(例如,即将到来的任务的提醒或简单的 "Goodbey USERNAME" 而不仅仅是 "Goodbey")...

所以我需要 access/use 当前注销用户的详细信息。但是由于用户刚刚注销,我不能再访问用户对象了吗?

如何解决?

这是我使用的配置:

// config
security:
    ...  
    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email

    firewalls:
        main:
            ...
            logout:
                path: fos_user_security_logout
                target: /logoutpage


 // route
 <route id="user_logout" path="/logoutpage" methods="GET">
    <default key="_controller">AppBundle:Default:logout</default>
 </route> 


 // Controller action
 public function logoutAction() {
    $loggedOutUser = HOW_TO_GET_USER(???);

    $template = 'AppBundle:Default:logout.html.twig';
    return $this->render($template, array('user' => $loggedOutUser));
 }

干净的方法是将用户的 name/data 保存在侦听 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'

事件class

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' }

容易吧?一个有点肮脏的解决方案是创建一个请求侦听器,在每次请求时将用户名保存在会话闪存包中,以便您可以在注销页面模板中从那里获取它。