启用 "remember me" 时在 Symfony 2 应用程序中注销用户
Log user out in Symfony 2 application when "remember me" is enabled
我正在寻找一种方法让用户退出 Symfony 2 应用程序,但找不到正确的方法。
我已经尝试过此处描述的方法:
Symfony2: how to log user out manually in controller?
$this->get('security.context')->setToken(null);
$this->get('request')->getSession()->invalidate();
禁用“remember me”时它工作正常,但是,当我启用它时,它不工作。看起来用户被这个 cookie 自动重新验证了。
remember_me:
key: "%secret%"
lifetime: 31536000
path: /
domain: ~
always_remember_me: true
让用户退出 Symfony 2 应用程序的正确方法是什么?我是否需要从服务器端另外删除此 cookie?
您可能必须显式调用 session-storage 的 save()
(Documentation) 方法。
Force the session to be saved and closed.
此外,您可以要求删除 session- and/or remember_me-cookies通过响应 headers.
session-cookie 的名称配置为 container-parameter framework.session.name
并且默认为您的 session.name
值php.ini.
$cookieName = $this->container->getParameter('framework.session.name');
$response->headers->clearCookie( $cookieName );
remember_me-cookie 的名称可以在您的 security
配置中配置。
security:
firewalls:
your_firewall:
remember_me:
name: neverforget # <- cookie-name
感谢 @nifr 我能够解决这个问题。这是将用户手动退出 Symfony 2 应用程序的防弹分步指南。
警告
Symfony 已经实现了注销用户和删除cookie 的功能。有一个 LogoutListener
将这些操作委托给几个注销处理程序:CookieClearingLogoutHandler
和 SessionLogoutHandler
。我认为最好的做法是调用这些处理程序,而不是自己实现这种低级逻辑。但是,我找不到办法做到这一点。
解决方案
此解决方案适用于 Symfony 2.6。区别在于 security.token_storage
.
- 添加两个附加参数以将“会话”和“记住我”的 cookie 名称存储到您的
parameters.yml
:
# parameters.yml
parameters:
session.name: SESS
session.remember_me.name: LONGSESS
- 更新您的
config.yml
以使用会话名称的第一个参数:
# config.yml
framework:
session:
name: "%session.name%"
- 更新您的
security.yml
以使用第二个参数来记住我的会话名称:
# security.yml
security:
firewalls:
demo_secured_area:
remember_me:
name: "%session.remember_me.name%"
- 这是您可以用来注销当前用户的代码:
如果需要,您可以在内核事件侦听器中使用此类代码。
// SomeController.php
/**
* @Route("/terminate", name="app.terminate")
*/
public function terminateAction()
{
// Logging user out.
$this->get('security.token_storage')->setToken(null);
// Invalidating the session.
$session = $this->get('request')->getSession();
$session->invalidate();
// Redirecting user to login page in the end.
$response = $this->redirectToRoute('app.login');
// Clearing the cookies.
$cookieNames = [
$this->container->getParameter('session.name'),
$this->container->getParameter('session.remember_me.name'),
];
foreach ($cookieNames as $cookieName) {
$response->headers->clearCookie($cookieName);
}
return $response;
}
这是内核事件侦听器的实现,它会根据实体属性强制用户注销:Logging user out of Symfony 2 application using kernel event listener.
希望对您有所帮助。
@Slava Fomin II
Symfony already implements the functionality of logging user out and deleting cookies. There is a LogoutListener who delegates those action to couple of logout handlers: CookieClearingLogoutHandler and SessionLogoutHandler. I think the best course of action would be to call those handlers and not to implement such low-level logic yourself. However, I can't find a way to do this.
为什么不简单地创建一个调用这些服务的服务呢?
我调查了 Symfony\Component\Security\Http\Firewall\LogoutListener
并测试了他在注销期间调用了 2 个服务(Symfony 3.2.9)。
$tokenBasedRememberMeServices
顺便删除记住我的 cookie。
<?php declare(strict_types=1);
namespace MyProject\Security\Listener;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Logout\SessionLogoutHandler;
use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices;
final class LogoutListener
{
private $sessionLogoutHandler;
private $tokenBasedRememberMeServices;
private $defaultLogoutSuccessHandler;
private $tokenStorage;
public function __construct(
SessionLogoutHandler $sessionLogoutHandler,
TokenBasedRememberMeServices $tokenBasedRememberMeServices,
DefaultLogoutSuccessHandler $defaultLogoutSuccessHandler,
TokenStorage $tokenStorage
)
{
$this->sessionLogoutHandler = $sessionLogoutHandler;
$this->tokenBasedRememberMeServices = $tokenBasedRememberMeServices;
$this->defaultLogoutSuccessHandler = $defaultLogoutSuccessHandler;
$this->tokenStorage = $tokenStorage;
}
public function logout(Request $request): void
{
$token = $this->tokenStorage->getToken();
$response = $this->defaultLogoutSuccessHandler->onLogoutSuccess($request);
$this->sessionLogoutHandler->logout($request, $response, $token);
$this->tokenBasedRememberMeServices->logout($request, $response, $token);
}
}
我正在寻找一种方法让用户退出 Symfony 2 应用程序,但找不到正确的方法。
我已经尝试过此处描述的方法: Symfony2: how to log user out manually in controller?
$this->get('security.context')->setToken(null);
$this->get('request')->getSession()->invalidate();
禁用“remember me”时它工作正常,但是,当我启用它时,它不工作。看起来用户被这个 cookie 自动重新验证了。
remember_me:
key: "%secret%"
lifetime: 31536000
path: /
domain: ~
always_remember_me: true
让用户退出 Symfony 2 应用程序的正确方法是什么?我是否需要从服务器端另外删除此 cookie?
您可能必须显式调用 session-storage 的 save()
(Documentation) 方法。
Force the session to be saved and closed.
此外,您可以要求删除 session- and/or remember_me-cookies通过响应 headers.
session-cookie 的名称配置为 container-parameter framework.session.name
并且默认为您的 session.name
值php.ini.
$cookieName = $this->container->getParameter('framework.session.name');
$response->headers->clearCookie( $cookieName );
remember_me-cookie 的名称可以在您的 security
配置中配置。
security:
firewalls:
your_firewall:
remember_me:
name: neverforget # <- cookie-name
感谢 @nifr 我能够解决这个问题。这是将用户手动退出 Symfony 2 应用程序的防弹分步指南。
警告
Symfony 已经实现了注销用户和删除cookie 的功能。有一个 LogoutListener
将这些操作委托给几个注销处理程序:CookieClearingLogoutHandler
和 SessionLogoutHandler
。我认为最好的做法是调用这些处理程序,而不是自己实现这种低级逻辑。但是,我找不到办法做到这一点。
解决方案
此解决方案适用于 Symfony 2.6。区别在于 security.token_storage
.
- 添加两个附加参数以将“会话”和“记住我”的 cookie 名称存储到您的
parameters.yml
:
# parameters.yml
parameters:
session.name: SESS
session.remember_me.name: LONGSESS
- 更新您的
config.yml
以使用会话名称的第一个参数:
# config.yml
framework:
session:
name: "%session.name%"
- 更新您的
security.yml
以使用第二个参数来记住我的会话名称:
# security.yml
security:
firewalls:
demo_secured_area:
remember_me:
name: "%session.remember_me.name%"
- 这是您可以用来注销当前用户的代码:
如果需要,您可以在内核事件侦听器中使用此类代码。
// SomeController.php
/**
* @Route("/terminate", name="app.terminate")
*/
public function terminateAction()
{
// Logging user out.
$this->get('security.token_storage')->setToken(null);
// Invalidating the session.
$session = $this->get('request')->getSession();
$session->invalidate();
// Redirecting user to login page in the end.
$response = $this->redirectToRoute('app.login');
// Clearing the cookies.
$cookieNames = [
$this->container->getParameter('session.name'),
$this->container->getParameter('session.remember_me.name'),
];
foreach ($cookieNames as $cookieName) {
$response->headers->clearCookie($cookieName);
}
return $response;
}
这是内核事件侦听器的实现,它会根据实体属性强制用户注销:Logging user out of Symfony 2 application using kernel event listener.
希望对您有所帮助。
@Slava Fomin II
Symfony already implements the functionality of logging user out and deleting cookies. There is a LogoutListener who delegates those action to couple of logout handlers: CookieClearingLogoutHandler and SessionLogoutHandler. I think the best course of action would be to call those handlers and not to implement such low-level logic yourself. However, I can't find a way to do this.
为什么不简单地创建一个调用这些服务的服务呢?
我调查了 Symfony\Component\Security\Http\Firewall\LogoutListener
并测试了他在注销期间调用了 2 个服务(Symfony 3.2.9)。
$tokenBasedRememberMeServices
顺便删除记住我的 cookie。
<?php declare(strict_types=1);
namespace MyProject\Security\Listener;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Logout\SessionLogoutHandler;
use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices;
final class LogoutListener
{
private $sessionLogoutHandler;
private $tokenBasedRememberMeServices;
private $defaultLogoutSuccessHandler;
private $tokenStorage;
public function __construct(
SessionLogoutHandler $sessionLogoutHandler,
TokenBasedRememberMeServices $tokenBasedRememberMeServices,
DefaultLogoutSuccessHandler $defaultLogoutSuccessHandler,
TokenStorage $tokenStorage
)
{
$this->sessionLogoutHandler = $sessionLogoutHandler;
$this->tokenBasedRememberMeServices = $tokenBasedRememberMeServices;
$this->defaultLogoutSuccessHandler = $defaultLogoutSuccessHandler;
$this->tokenStorage = $tokenStorage;
}
public function logout(Request $request): void
{
$token = $this->tokenStorage->getToken();
$response = $this->defaultLogoutSuccessHandler->onLogoutSuccess($request);
$this->sessionLogoutHandler->logout($request, $response, $token);
$this->tokenBasedRememberMeServices->logout($request, $response, $token);
}
}