手动创建 symfony2 记住我 cookie (FOSUserBundle)

发布于 2024-12-28 09:00:51 字数 2922 浏览 0 评论 0原文

有人可以解释一下如何在控制器中手动创建记住我的 cookie 吗?

我希望用户在按下“注册”后保持登录状态 按钮,之后无需使用其凭据登录。

我尝试过手动创建 cookie,但我猜测 cookie 值不正确,因此“记住我”功能 不起作用。 设置具有正确名称的 cookie。我已经查过了。

使用正常模式时,“记住我”功能可以按预期工作 使用用户凭据的登录过程。

安全.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:

我尝试了第三种方法。与上面相同但没有反射:

$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);

Could somebody explain how you can manually create a remember me cookie in a controller?

I want the users to stay logged in after they pressed the "register"
button, without having to login with their credentials afterwards.

I've tried to create a cookie manually but i'm guessing the cookie
value is incorrect, and therefor the "remember me" functionality
doesn't work.
A cookie with the correct name gets set. I've checked that.

The remember me functionality works as expected when using the normal
login procedure with the user's credentials.

security.yml
security.yml remember me

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

This is what I have now, even though the cookie is set, it doesn't work.

$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;

Update:

I've also tried working with the
PersistentTokenBasedRememberMeServices class with reflection but it does not work. a cookie gets set but it's not working

$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);

I'm using Symfony v2.0.5 and FOSUserBundle 1.0

UPDATE 2:

I've tried a 3rd way. The same as above but without reflection:

$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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

别把无礼当个性 2025-01-04 09:00:51

我是这样做的。我没有使用 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 参数中,否则AbstractRememberMeServices 的方法 isRememberMeRequested 将返回 false,并且不会存储 cookie。

不过,您已经非常接近正确的解决方案了:)您做错了(在第三次尝试中)是您更改了此处参数的顺序:

$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 作为第二个参数传递,将 $providerKey 作为第三个参数传递,而不是像您错误地那样传递相反的方式;)

我还不知道,是如何直接在控制器中从 security.yml 获取参数而不是重复它。通过使用 $this->container->getParameter() 我可以获取存储在 config.yml 中 parameters 键下的参数,但不能获取配置中较高位置的参数树。对此有什么想法吗?

Here is how I did it. I'm not using the FOSUserBundle and I'm using Doctrine Entity User Provider, but it should be trivial to adjust to your needs. Here is a general solution:

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

Just remember you have to set always_remember_me option to true (like I did in the code above) or have it in your $_POST parameters somehow, otherwise method isRememberMeRequested of AbstractRememberMeServices will return false and the cookie won't be stored.

You were pretty close to the correct solution though :) What you did wrong (in the 3rd attempt) is that you've changed the order of parameters here:

$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'));

Take a look at __construct() in AbstractRememberMeServices.php. You should pass a $securityKey as 2nd argument and $providerKey as 3rd argument, not the other way around like you did by mistake ;)

What I don't know yet, is how to get parameters from security.yml directly in the controller not to duplicate it. By using $this->container->getParameter() I can get parameters stored under parameters key in config.yml, but not the ones places higher in the configuration tree. Any thoughts on this?

甜点 2025-01-04 09:00:51

如果您直接设置 Rememberme Cookie,则必须使用以下格式:

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

哈希值的位置:

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

密钥是您在 remember_me 部分。

这是取自 Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeService.php 文件中的 processAutoLoginCookie() 方法。

这都是由同一个类中的 generateCookieValue() 方法完成的。

不过,我不建议直接使用这种方式,而是尝试看看是否可以调用 TokenBasedRememberMeService::onLoginSuccess() 方法,该方法会为您设置此 cookie,以使代码更加健壮和便携式。

If you are setting the rememberme cookie directly, you have to use the following format:

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

where the hash will be:

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

the key is the key you have entered in your security(.xml/.yml) in the remember_me section.

This is taken from processAutoLoginCookie() method in the Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeService.php file.

This is all done by the generateCookieValue() method in the same class.

However, I would not recommend on using doing it this way directly, but try to see if you can call the TokenBasedRememberMeService::onLoginSuccess() method, which sets this cookie for you to make the code more robust and portable.

云之铃。 2025-01-04 09:00:51

对我来说,最简单的解决方案是扩展 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.

For me the easiest solution was extend a BaseTokenBasedRememberMeServices and let it handle

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;
    }
}

and in controller;

$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());

then response set cookie to $remember_me_cookie

I hope its works with you 2.

寂寞美少年 2025-01-04 09:00:51

当我尝试使用 守卫身份验证

在这种情况下,我没有 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
);

I had the same issue when I tried to set REMEMBERME cookie an User after a connection by token, using Guard Authentication.

In this situation I had no Response object to be able to use $response->headers->setCookie() and needs to use setcookie().
And in this situation, create a RedirectResponse is not appropriate.

This needs to be refactored but I post the raw procedural on which I based my service

$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
);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文