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 年以来仍未修复。
我找到的解决方案是在我自己的用户包中实现 this PR。
注意:这适用于 1.3,还没有尝试 2.0
- 添加此编译器传递:
/*
* 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);
}
}
- 在您的包的构建中实例化它:
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());
}
}
- 完全覆盖登录管理器:
/*
* 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());
}
}
同时在您的 services.yml 文件中覆盖其服务声明:
services:
# ...
fos_user.security.login_manager:
class: AppUserBundle\Security\LoginManager
arguments:
- @security.context
- @security.user_checker
- @security.authentication.session_strategy
- @service_container
- { }
最后,在您的 register.html.twig 模板上添加 remember_me 复选框:
<input type="checkbox" id="remember_me" name="_remember_me" checked />
<label for="remember_me">Keep me logged in</label>
我正在尝试在用户注册时设置 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 年以来仍未修复。 我找到的解决方案是在我自己的用户包中实现 this PR。
注意:这适用于 1.3,还没有尝试 2.0
- 添加此编译器传递:
/*
* 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);
}
}
- 在您的包的构建中实例化它:
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());
}
}
- 完全覆盖登录管理器:
/*
* 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());
}
}
同时在您的 services.yml 文件中覆盖其服务声明:
services: # ... fos_user.security.login_manager: class: AppUserBundle\Security\LoginManager arguments: - @security.context - @security.user_checker - @security.authentication.session_strategy - @service_container - { }
最后,在您的 register.html.twig 模板上添加 remember_me 复选框:
<input type="checkbox" id="remember_me" name="_remember_me" checked /> <label for="remember_me">Keep me logged in</label>