启用“记住我”时,在 Symfony 2 应用程序中注销用户
Posted
技术标签:
【中文标题】启用“记住我”时,在 Symfony 2 应用程序中注销用户【英文标题】:Log user out in Symfony 2 application when "remember me" is enabled 【发布时间】:2015-05-03 20:17:20 【问题描述】:我正在寻找一种让用户退出 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 吗?
【问题讨论】:
【参考方案1】:感谢@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。
希望对你有帮助。
【讨论】:
请注意,如果您在session
配置中使用domain
设置,则必须将此值设置为clearCookie
中的第三个参数。
您应该在清除 cookie 后使用 $response->send();
以使其正常工作。【参考方案2】:
您可能必须显式调用会话存储的save()
(Documentation) 方法。
强制保存并关闭会话。
您还可以通过响应标头请求删除 session- 和/或 remember_me-cookie。
session-cookie 的名称配置为容器参数 framework.session.name
,默认为 php.ini 中的 session.name
值。
$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
【讨论】:
您清除缓存了吗?请清除您的浏览器缓存/cookies 和 symfony 的缓存 - 应该可以工作。否则你的ini_get('session.name');
设置是什么?
手动删除 cookie 有助于解决问题,谢谢!
我只是好奇,是否可以将其委托给 Symfony?我认为这将是一个更好的方法。
把这个委托给 symfony 是什么意思? ...创建一个响应侦听器,如果满足某些条件则执行注销?
不,我的意思是,Symfony 已经实现了注销用户和终止 cookie 的功能。有一个 LogoutListener
将这些操作委托给几个注销处理程序:CookieClearingLogoutHandler
和 SessionLogoutHandler
。我认为最好的做法是调用这些处理程序,而不是自己实现这样的低级逻辑。【参考方案3】:
@Slava Fomin II
Symfony 已经实现了注销用户和删除 cookie 的功能。有一个 LogoutListener 将这些操作委托给几个注销处理程序:CookieClearingLogoutHandler 和 SessionLogoutHandler。我认为最好的做法是调用这些处理程序,而不是自己实现这样的低级逻辑。但是,我找不到这样做的方法。
为什么不简单地创建一个调用它们的服务?
我查看了Symfony\Component\Security\Http\Firewall\LogoutListener
并测试了他在注销期间调用了 2 个服务(Symfony 3.2.9)。
$tokenBasedRememberMeServices
顺便删除了remember-me 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 在新版本中改进了它的身份验证处理架构。我目前没有使用 Symfony,因为我已经切换到 Node.js,所以我无法验证您的答案。对不起!但我希望它会对某人有所帮助。 对于 Symfony3.2.9
我没有找到任何提供的解决方案。希望我能帮助别人解决我的问题。
我的第一个问题是,这个解决方案是否仍然适用于 Symfony 4?其次,使用 Listener/Subscriber 的任何具体原因?为什么不直接使用常规服务,将其注入 Controller 并在那里调用它的注销方法。以上是关于启用“记住我”时,在 Symfony 2 应用程序中注销用户的主要内容,如果未能解决你的问题,请参考以下文章
在 Symfony 应用程序/控制台中启用 Doctrine DBAL 命令
在 symfony 中为 @babel/plugin-proposal-class-properties 启用 classProperties