Symfony2 guard inactive session lifetime

792 Views Asked by At

I try to expire user session if it's inactive for X seconds. I've find many solutions to do that, but not for an inactive session.

I use Symfony2 with Guard Authentification. I've implemented this solution, which seems not bad. But the session expire, even if the user is active. I probably miss something. Is there any particularity to use Guard that can affect session time ?

My Authenticator :

<?php

namespace AppBundle\Security;


class TokenAuthenticator extends AbstractGuardAuthenticator
{
    /**
   * @var \Symfony\Component\Routing\RouterInterface
   */
    private $router;
    
    /*
     * Url d'accès au WebService d'authentification
     */
    private $urlWs;
  
    /**
     * Constructeur
     * @param RouterInterface $router
     * @param string $urlWs : Url d'accès au WebService d'authentification
     */
    public function __construct(RouterInterface $router, $urlWs) {
        $this->router = $router;
        $this->urlWs = $urlWs;
    }


    /**
     * Called on every request. Return whatever credentials you want,
     * or null to stop authentication.
     */
    public function getCredentials(Request $request)
    {
        if ($request->getPathInfo() != "/login_check"){
            return;
        }
        
        // What you return here will be passed to getUser() as $credentials
        return [
            'login' => $request->request->get('username'),
            'password' => $request->request->get('password'),
            'request' => $request,
        ];
    }

    /**
     * 
     * @param type $credentials
     * @param UserProviderInterface $userProvider
     * @return User
     */
    public function getUser($credentials, UserProviderInterface $userProvider)
    {
       $login = $credentials['login'];
        
       $user = new User();
       $user->setLogin($login);
       
       return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {        
        $username = $credentials['login'];
        $password = $credentials['password'];           
        try {
                /**********************************
                Call my WebService to control the login password
                If it's ok, I save the returned user in session
                *****************************************/
                
                return true;
            } else {
                throw new CustomUserMessageAuthenticationException($ws_response->messages[0]);
            }               
        }catch(\Exception $e){
            throw $e;
        }  
    }
    

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        $session = $request->getSession();     
        $url = "/";
        return new RedirectResponse($url);
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
        $url = $this->router->generate('loginSf');
        return new RedirectResponse($url);
    }

    /**
     * Called when authentication is needed, but it's not sent
     */
    public function start(Request $request, AuthenticationException $authException = null)
    {
        $url = $this->router->generate('loginSf');
        return new RedirectResponse($url);
    }

    public function supportsRememberMe()
    {
        return false;
    }
}

My session handler:

<?php

namespace AppBundle\Handler;

class SessionIdleHandler
{

    protected $session;
    protected $securityContext;
    protected $router;
    protected $maxIdleTime;

    public function __construct(SessionInterface $session, SecurityContextInterface $securityContext, RouterInterface $router, $maxIdleTime = 0)
    {
        $this->session = $session;
        $this->securityContext = $securityContext;
        $this->router = $router;
        $this->maxIdleTime = $maxIdleTime;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) {

            return;
        }

        if ($this->maxIdleTime > 0) {

            $this->session->start();
            $lapse = time() - $this->session->getMetadataBag()->getLastUsed();

            if ($lapse > $this->maxIdleTime) {

                $this->securityContext->setToken(null);
                $this->session->getFlashBag()->set('info', 'You have been logged out due to inactivity.');

                $event->setResponse(new RedirectResponse($this->router->generate('loginSf')));
            }
        }
    }

}

service.yml:

services:
    my.handler.session_idle:
        class: AppBundle\Handler\SessionIdleHandler
        arguments: ["@session", "@security.context", "@router", %sessionLifeTime%]
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

config.yml:

framework:
    secret:          "%secret%"
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
        strict_requirements: ~
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    templating:
        engines: ['twig']
    default_locale:  "%locale%"
    trusted_hosts:   ~
    trusted_proxies: ~
    session:
        cookie_lifetime: %sessionLifeTime% 
        # handler_id set to null will use default session handler from php.ini
        handler_id:  ~
    fragments:       ~
    http_method_override: true

And in parameters.yml I've this : sessionLifeTime: 0

I found this option too, but is it a solution to my problem?

2

There are 2 best solutions below

0
On BEST ANSWER

Thank's for your help,

I do not understand what I've done. I've tested your solution (so I comment my Session Handler) to put gc_maxlifetime on config.yml, but my problem was still there.

So I've uncomment my session handler, finally I returned to the code I've post before... and now it works...

Sorry I can't explain that. I've cleared the cache many times, so I think it's not the reason.

1
On

The easiest way is to implement this via garbage collection which runs reasonably frequently.

You got a paragraph on the symfony doc concerning idle time session.

http://symfony.com/doc/current/components/http_foundation/session_configuration.html#session-idle-time-keep-alive