Создать symfony2 запомнить меня cookie вручную (FOSUserBundle) - PullRequest
8 голосов
/ 22 января 2012

Может ли кто-нибудь объяснить, как вы можете вручную создать cookie-файл Запомнить меня в контроллере?

Я хочу, чтобы пользователи оставались в системе после того, как они нажали кнопку «зарегистрироваться», без необходимости впоследствии входить со своими учетными данными.

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

Функциональность запомнить меня работает, как и ожидалось, при использовании обычной процедуры входа в систему с учетными данными пользователя.

security.yml security.yml запомнить меня

security:
   firewalls:
       main:
           remember_me:
               lifetime: 86400
               domain:   ~
               path:     /
               key:      myKey

Это то, что у меня есть сейчас, хотя cookie и установлен, он не работает.

$um = $this->get('fos_user.user_manager');
$member = $um->createUser();

… Form stuff with bindRequest etc.

$um->updatePassword($member);
$um->updateUser($member);

$providerKey = $this->container->getParameter('fos_user.firewall_name');
$securityKey = 'myKey';

$token = new RememberMeToken($member, $providerKey, $securityKey,
$member->getRoles());
$this->container->get('security.context')->setToken($token);

$redirectResponse = new RedirectResponse($url);
$redirectResponse->headers->setCookie(
   new \Symfony\Component\HttpFoundation\Cookie(
       'REMEMBERME',
       base64_encode(implode(':', array($member->getUsername(),
$member->getPassword()))),
       time() + 60*60*24
   )
);
return $redirectResponse;

Обновление:

Я также пытался работать с классом PersistentTokenBasedRememberMeServices с отражением, но он не работает.устанавливается cookie, но он не работает

$token = $this->container->get('security.context')->getToken();

$providerKey = $this->container->getParameter('fos_user.firewall_name');
$securityKey = 'myKey';

$persistenService = new
PersistentTokenBasedRememberMeServices(array($um), $providerKey,
$securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' =>
null, 'secure' => false, 'httponly' => true,
'lifetime' => 86400));
$persistenService->setTokenProvider(new InMemoryTokenProvider());

$method = new \ReflectionMethod('Symfony\Component\Security\Http\RememberMe\PersistentTokenBasedRememberMeServices',
'onLoginSuccess');
 $method->setAccessible(true);
$method->invoke($persistenService, $request, $redirectResponse, $token);

Я использую Symfony v2.0.5 и FOSUserBundle 1.0

ОБНОВЛЕНИЕ 2:

Я пробовал 3-й способ,То же, что и выше, но без отражения:

$token = $this->container->get('security.context')->getToken();

$providerKey = $this->container->getParameter('fos_user.firewall_name');
$securityKey = 'myKey';

$persistenService = new PersistentTokenBasedRememberMeServices(array($um), $providerKey, $securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' => null, 'secure' => false, 'httponly' => true, 'lifetime' => 31536000, 'always_remember_me' => true, 'remember_me_parameter' => '_remember_me'));
$persistenService->setTokenProvider(new InMemoryTokenProvider());

$persistenService->loginSuccess($request, $redirectResponse, $token);

Ответы [ 4 ]

13 голосов
/ 31 января 2012

Вот как я это сделал.Я не использую FOSUserBundle, а использую Doctrine Entity User Provider, но это должно быть тривиально, чтобы приспособиться к вашим потребностям.Вот общее решение:

// after registration and persisting the user object to DB, I'm logging the user in automatically
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());

// but you can also get the token directly, if you're user is already logged in
$token = $this->container->get('security.context')->getToken();

// write cookie for persistent session storing
$providerKey = 'main'; // defined in security.yml
$securityKey = 'MySecret'; // defined in security.yml

$userProvider = new EntityUserProvider($this->getDoctrine()->getEntityManager(), 'MyCompany\MyBundle\Entity\User', 'username');

$rememberMeService = new TokenBasedRememberMeServices(array($userProvider), $securityKey, $providerKey, array(
                'path' => '/',
                'name' => 'MyRememberMeCookie',
                'domain' => null,
                'secure' => false,
                'httponly' => true,
                'lifetime' => 1209600, // 14 days
                'always_remember_me' => true,
                'remember_me_parameter' => '_remember_me')
            );

$response = new Response();
$rememberMeService->loginSuccess($request, $response, $token);

// further modify the response
// ........

return $response;

Просто помните, что вы должны установить always_remember_me option в true (как я это делал в приведенном выше коде) или как-то в параметрах $ _POST, иначе метод isRememberMeRequested из AbstractRememberMeServices вернет значение false, и файл cookie не будет сохранен.

Хотя вы были достаточно близки к правильному решению :) Что вы сделали не так (в 3-й попытке), так это то, что выизменил порядок параметров здесь:

$persistenService = new PersistentTokenBasedRememberMeServices(array($um), $providerKey, $securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' => null, 'secure' => false, 'httponly' => true, 'lifetime' => 31536000, 'always_remember_me' => true, 'remember_me_parameter' => '_remember_me'));

Взгляните на __construct() in AbstractRememberMeServices.php.Вы должны передать $securityKey в качестве 2-го аргумента и $providerKey в качестве 3-го аргумента, а не наоборот, как вы сделали по ошибке;)

Что я пока не знаю, это как получить параметры изsecurity.yml прямо в контроллере, чтобы не дублировать его.Используя $this->container->getParameter(), я могу получить параметры, хранящиеся под ключом parameters в config.yml, но не те, которые находятся выше в дереве конфигурации.Есть мысли по этому поводу?

10 голосов
/ 30 января 2012

Если вы устанавливаете cookie-файл Rememberme напрямую, вы должны использовать следующий формат:

base64_encode(<classname>:base64_encode(<username>):<expiry-timestamp>:<hash>)

где хеш будет:

sha256(<classname> . <username> . <expiry-timestamp> . <password> . <key>)

ключ - это ключ, который выввели в вашу безопасность (.xml / .yml) в разделе remember_me.

Это взято из метода processAutoLoginCookie() в Symfony / Component / Security / Http / RememberMe / TokenBasedRememberMeService.php file.

Все это делается методом generateCookieValue() в том же классе.

Однако я бы не рекомендовал использовать это напрямую, но постараюсь выяснить, можно ли вызвать метод TokenBasedRememberMeService::onLoginSuccess(), который устанавливает этот файл cookie для того, чтобы сделать код более надежным и переносимым.

0 голосов
/ 30 марта 2017

У меня была такая же проблема, когда я пытался установить REMEMBERME cookie для пользователя после подключения по токену, используя Guard Authentication .

В этой ситуации у меня не было объекта Response, чтобы можно было использовать $ response-> headers-> setCookie (), и мне нужно было использовать setcookie (). И в этой ситуации создание RedirectResponse не подходит.

Требуется рефакторинг, но я публикую сырую процедурную информацию, на которой я основал свой сервис

$expires = time() + 2628000;
$hash = hash_hmac(
    'sha256',
     get_class($user).$user->getUsername().$expires.$user->getPassword(), 'secret in parameters.yml'
);
$value = base64_encode(implode(':', [get_class($user), base64_encode($user->getUsername()), $expires, $hash]));
setcookie(
    'REMEMBERME',
    $value,
    $expires,
    '/',
    'host',
    'ssl boolean',
    true
);
0 голосов
/ 13 января 2017

Для меня самым простым решением было расширить BaseTokenBasedRememberMeServices и позволить ему обрабатывать

namespace AppBundke\Security\Http;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices as BaseTokenBasedRememberMeServices;


class TokenBasedRememberMeServices extends BaseTokenBasedRememberMeServices
{
     protected $options_new = array('name' => 'REMEMBERME', 'domain' => null, 'path' => '/');

     public function __construct($userProvider, $secret, $providerKey, array $options = array(), LoggerInterface $logger = null)
     {
          return parent::__construct(array($userProvider), $secret, $providerKey, array_merge($this->options_new, $options));
     }

     public function generateCookie($user, $username, $expires, $password)
     {
        $cookie = new Cookie(
             $this->options['name'],
             parent::generateCookieValue(get_class($user), $username, $expires, $password),
             $expires,
             $this->options['path'],
             $this->options['domain'],
             $this->options['secure'],
             $this->options['httponly']
        );
    return $cookie;
    }
}

и в контроллере;

$user = $this->getUser();
$providerKey = $this->getParameter('fos_user.firewall_name');
$secret = $this->getParameter('secret');
$cookie_life_time = $this->getParameter('cookie_life_time');

$remember_me_service = new TokenBasedRememberMeServices($user, $secret, $providerKey );
$remember_me_cookie = $remember_me_service->generateCookie($user, $user->getUsername(),(time() + $cookie_life_time), $user->getPassword());

тогда ответ устанавливает cookie на $ Remember_me_cookie

Я надеюсь, что это работает с вами 2.

...