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