Пользовательский пакет Symfony2/FOS - Запомните меня после регистрации


Я пытаюсь установить файл cookie REMEMBERME при регистрации пользователя. Мои пользователи входят в систему сразу после регистрации, без подтверждения по электронной почте.

Я не хочу использовать функцию always_remember_me, потому что я все еще хочу, чтобы пользователь установил флажок.

Я нашел эту функцию, вызываемую контроллером регистрации FOS:

В FOS\UserBundle\Безопасность\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);
}

Похоже, это вызывает службу "Запомни меня" и устанавливает токен. К несчастью это не срабатывает, потому что у меня их нет.

Как я могу создать службу "Запомни меня"? Есть ли более простой способ установить файл cookie REMEMBERME в реестре?

Спасибо.

Author: Artggd, 2015-11-16

1 answers

Похоже, это старая ошибка, все еще не исправленная с 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 <[email protected]>
 */
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 <[email protected]>
 */
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. Также переопределяет его службу декларация в ваших услугах.файл yml:

    services:
        # ...
            fos_user.security.login_manager:
                class: AppUserBundle\Security\LoginManager
                arguments:
                    - @security.context
                    - @security.user_checker
                    - @security.authentication.session_strategy
                    - @service_container
                    - { }
    
  2. Наконец, добавьте флажок remember_me в свой шаблон register.html.twig:

    <input type="checkbox" id="remember_me" name="_remember_me" checked />
    <label for="remember_me">Keep me logged in</label>
    
 1
Author: Artggd, 2015-11-18 23:16:29