Symfony2/FOS用户捆绑包-注册后请记住我


Symfony2 / FOS user bundle - Remember me after registration

我正在尝试在用户注册时设置REMEMBERME cookie。我的用户在注册后直接登录,无需确认电子邮件。

我不想使用always_remember_me功能,因为我仍然希望用户选择复选框。

我发现FOS的RegistrationController调用了这个函数:

在FOS''UserBundle''Security''LoginManager 中

final public function loginUser($firewallName, UserInterface $user, Response $response = null)
{
    $this->userChecker->checkPostAuth($user);
    $token = $this->createToken($firewallName, $user);
    if ($this->container->isScopeActive('request')) {
        $this->sessionStrategy->onAuthentication($this->container->get('request'), $token);
        if (null !== $response) {
            $rememberMeServices = null;
            if ($this->container->has('security.authentication.rememberme.services.persistent.'.$firewallName)) {
                $rememberMeServices = $this->container->get('security.authentication.rememberme.services.persistent.'.$firewallName);
            } elseif ($this->container->has('security.authentication.rememberme.services.simplehash.'.$firewallName)) {
                $rememberMeServices = $this->container->get('security.authentication.rememberme.services.simplehash.'.$firewallName);
            }
            if ($rememberMeServices instanceof RememberMeServicesInterface) {
                $rememberMeServices->loginSuccess($this->container->get('request'), $response, $token);
            }
        }
    }
    $this->securityContext->setToken($token);
}

这似乎调用了"记住我"服务并设置了令牌。不幸的是,它没有被触发,因为我没有。

如何创建"记住我"服务?有没有更简单的方法可以在注册时设置REMEMBERME cookie?

谢谢。

这似乎是一个旧错误,自2012年以来仍未修复。我找到的解决方案是在我自己的用户包中实现这个PR。

注意:这适用于1.3,还没有尝试2.0

  1. 添加此编译器过程:

/*
 * This file is part of the FOSUserBundle package.
 *
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace AppUserBundle'DependencyInjection'Compiler;
use Symfony'Component'DependencyInjection'ContainerBuilder;
use Symfony'Component'DependencyInjection'Compiler'CompilerPassInterface;
use Symfony'Component'DependencyInjection'Reference;
/**
 * Registers the additional validators according to the storage
 *
 * @author Vasily Khayrulin <sirianru@gmail.com>
 */
class InjectRememberMeServicesPass implements CompilerPassInterface
{
    /**
     * {@inheritDoc}
     */
    public function process(ContainerBuilder $container)
    {
        $rememberMeServices = array();
        foreach ($container->getDefinitions() as $id => $definition) {
            if (0 !== strpos($id, 'security.authentication.rememberme.services.')) {
                continue;
            }
            if ($definition->isAbstract()) {
                continue;
            }
            $firewallName = $definition->getArgument(2);
            $rememberMeServices[$firewallName] = new Reference($id);
        }
        $loginManager = $container->getDefinition('fos_user.security.login_manager');
        $loginManager->replaceArgument(4, $rememberMeServices);
    }
}

  1. 在捆绑包的构建中实例化它:

namespace AppUserBundle;
use Symfony'Component'DependencyInjection'ContainerBuilder;
use Symfony'Component'HttpKernel'Bundle'Bundle;
use AppUserBundle'DependencyInjection'Compiler'InjectRememberMeServicesPass;
class AppUserBundle extends Bundle
{
    public function getParent()
    {
        return 'FOSUserBundle';
    }
    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        $container->addCompilerPass(new InjectRememberMeServicesPass());
    }
}

  1. 完全覆盖LoginManager:

/*
 * This file is part of the FOSUserBundle package.
 *
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace AppUserBundle'Security;
use FOS'UserBundle'Model'UserInterface;
use FOS'UserBundle'Security'LoginManagerInterface;
use Symfony'Component'DependencyInjection'ContainerInterface;
use Symfony'Component'HttpFoundation'Response;
use Symfony'Component'Security'Core'Authentication'Token'UsernamePasswordToken;
use Symfony'Component'Security'Core'User'UserCheckerInterface;
use Symfony'Component'Security'Core'SecurityContextInterface;
use Symfony'Component'Security'Http'RememberMe'AbstractRememberMeServices;
use Symfony'Component'Security'Http'RememberMe'RememberMeServicesInterface;
use Symfony'Component'Security'Http'Session'SessionAuthenticationStrategyInterface;
/**
 * Abstracts process for manually logging in a user.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class LoginManager implements LoginManagerInterface
{
    private $securityContext;
    private $userChecker;
    private $sessionStrategy;
    private $container;
    /**
     * @var AbstractRememberMeServices[]
     */
    private $rememberMeServices;
    public function __construct(
        SecurityContextInterface $context,
        UserCheckerInterface $userChecker,
        SessionAuthenticationStrategyInterface $sessionStrategy,
        ContainerInterface $container,
        $rememberMeServices
    ) {
        $this->securityContext    = $context;
        $this->userChecker        = $userChecker;
        $this->sessionStrategy    = $sessionStrategy;
        $this->container          = $container;
        $this->rememberMeServices = $rememberMeServices;
    }
    final public function loginUser($firewallName, UserInterface $user, Response $response = null)
    {
        $this->userChecker->checkPostAuth($user);
        $token = $this->createToken($firewallName, $user);
        if ($this->container->isScopeActive('request')) {
            $this->sessionStrategy->onAuthentication($this->container->get('request'), $token);
            if (null !== $response && isset( $this->rememberMeServices[$firewallName] )) {
                $rememberMeServices = $this->rememberMeServices[$firewallName];
                if ($rememberMeServices instanceof RememberMeServicesInterface) {
                    $rememberMeServices->loginSuccess($this->container->get('request'), $response, $token);
                }
            }
        }
        $this->securityContext->setToken($token);
    }
    protected function createToken($firewall, UserInterface $user)
    {
        return new UsernamePasswordToken($user, null, $firewall, $user->getRoles());
    }
}

  1. 还要覆盖services.yml文件中的服务声明:

    services:
        # ...
            fos_user.security.login_manager:
                class: AppUserBundle'Security'LoginManager
                arguments:
                    - @security.context
                    - @security.user_checker
                    - @security.authentication.session_strategy
                    - @service_container
                    - { }
    
  2. 最后,在register.html.twig模板上添加remember_me复选框:

    <input type="checkbox" id="remember_me" name="_remember_me" checked />
    <label for="remember_me">Keep me logged in</label>