启用“记住我”时,在Symfony 2应用程序中注销用户

时间:2015-03-03 08:46:04

标签: php security symfony authentication logout

我正在寻找一种方法将用户从Symfony 2应用程序中注销,但找不到合适的方法。

我尝试过这里描述的方法: Symfony2: how to log user out manually in controller?

$this->get('security.context')->setToken(null);
$this->get('request')->getSession()->invalidate();
当" remember me"" {{3}}"但是,当我启用它时,它被禁用,它无效。看起来这个cookie会再次自动重新验证用户。

remember_me:
    key:      "%secret%"
    lifetime: 31536000
    path:     /
    domain:   ~
    always_remember_me: true

将用户退出Symfony 2应用程序的正确方法是什么?我是否还需要从服务器端另外删除此cookie?

4 个答案:

答案 0 :(得分:11)

感谢@nifr我能够解决此问题。以下是手动将用户退出Symfony 2应用程序的防弹分步指南。

警告

Symfony已经实现了将用户注销和删除cookie的功能。有LogoutListener人将这些操作委派给几个注销处理程序:CookieClearingLogoutHandlerSessionLogoutHandler。我认为最好的做法是调用那些处理程序而不是自己实现这种低级逻辑。但是,我找不到办法做到这一点。

解决方案

此解决方案适用于Symfony 2.6。区别在于security.token_storage

  1. 添加两个额外的参数来存储«session»和«remember me»的cookie名称到你的parameters.yml
  2. # parameters.yml
    
    parameters:
        session.name: SESS
        session.remember_me.name: LONGSESS
    
    1. 更新您的config.yml以使用会话名称的第一个参数:
    2. # config.yml
      
      framework:
          session:
              name: "%session.name%"
      
      1. 更新您的security.yml以使用第二个参数记住我的会话名称:
      2. # security.yml
        
        security:
            firewalls:
                demo_secured_area:
                    remember_me:
                        name: "%session.remember_me.name%"
        
        1. 以下是您可以用来记录当前用户的代码:
        2. 如果需要,可以在内核事件侦听器中使用此类代码。

          // 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

          我希望它有所帮助。

答案 1 :(得分:4)

您可能必须明确调用会话存储的save()Documentation)方法。

  

强制保存并关闭会话。

此外,您可以通过回复标题请求删除会话 - 和/或 remember_me -cookies。

会话 -cookie的名称配置为容器参数framework.session.name,默认为 php.ini 中的session.name值。

$cookieName = $this->container->getParameter('framework.session.name');
$response->headers->clearCookie( $cookieName );

可以在security配置中配置 remember_me -cookie的名称。

security:
    firewalls:
        your_firewall:
            remember_me: 
                name: neverforget # <- cookie-name

答案 2 :(得分:1)

@Slava Fomin II

  

Symfony已经实现了将用户注销和删除cookie的功能。有一个LogoutListener将这些操作委托给几个注销处理程序:CookieClearingLogoutHandler和SessionLogoutHandler。我认为最好的做法是调用那些处理程序而不是自己实现这种低级逻辑。但是,我找不到办法做到这一点。

为什么不简单地创建一个调用它们的服务?

我调查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);
    }

}

答案 3 :(得分:0)

在您的security.yaml中,您可以使用它(除其他外,此示例仅是此示例的代码):

security:
    firewalls:
        main:
            logout:
                path: app_logout
                target: /login
                invalidate_session: true

然后您可以执行以下操作以注销用户:

return $this->redirectToRoute('app_logout');