Reputation: 5607
I'm using Symfony 2.3 LTS.
I can fully use the remember_me
feature in Symfony, including setting it and logging back in after session expiry. However my issue is that once the user is logged back in with the remember_me
feature then the expiry isn't refreshed.
In other words, if you set the "lifetime" of the remember_me
cookie to 14 days then regardless of how many time the user visits the site they will always need to re-authenticate with a full username/password (after 14 days.) I don't want to set a longer cookie as 14 days without visiting seems right.
I know how to manually set the remember_me
cookie. I just need to know where to put that code.
I've tried these:
This SO question doesn't do what I want and is very different.
There doesn't appear to be any settings in the security.yml
configuration (to refresh expiry.)
Hooking in on the processAutoLoginCookie
method in Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices
, but that can't work as there's no access to a Response (to set the cookie manually.)
Listening on the SecurityEvents::INTERACTIVE_LOGIN
event looks a good idea, but InteractiveLoginEvent
doesn't have access to the Response either. Here's an example.
I could get messy by setting a request attribute using one of the above and then setting a response listener to detect for that, but I think that's too messy. There must be a better way to do it.
I could use one of the above to listen on the request, generate a response (e.g. redirect), set the cookie, perform the redirect, but again that's not good enough.
Upvotes: 5
Views: 1423
Reputation: 1
The expiry timestamp and the password are both part of the hash of the cookie value, so it seems that the rememberme cookie can only be set at login since the password must be available to extend the timestamp.
From https://stackoverflow.com/a/9069098:
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>)
Upvotes: 0
Reputation: 16502
My proposed approach:
kernel.response
listenerSecurityContext
to the listener constructorremember_me
cookieremember_me
cookie.services:
acme.response_listener:
class: AcmeBundle\EventListener\ResponseListener
arguments: ['@security.context']
tags:
- { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }
namespace AcmeBundle\EventListener;
use Symfony\Component\Security\Http\Event\FilterResponseEvent;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\Cookie;
class ResponseListener
{
/** @var \Symfony\Component\Security\Core\SecurityContext */
private $securityContext;
/**
* Constructor
*
* @param SecurityContext $securityContext
*/
public function __construct(SecurityContext $securityContext)
{
$this->securityContext = $securityContext;
}
public function onKernelResponse(FilterResponseEvent $event)
{
$session = $event->getRequest()->getSession();
if (
$this->securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED') // remember_me cookie used
&& !$session->get('cookie_extended') // cookie hasn't been extended
) {
$response = $event->getResponse(); // get the Response object
$cookie = new Cookie(...); // your cookie
$response->headers->setCookie($cookie); // set that cookie!
$session->set('cookie_extended', true); // prevent future cookie sets for the current session
}
}
}
I haven't tested this code but it should be enough theory to get you started in this direction.
Upvotes: 3