0

I have a Symfony 2.5 project with the FOSUserBundle integrated. I want any logged in user with X amount of idle time on the app to be automatically logged out and redirected to the sign in page.

So far I've implemented a solution, that is quite similar to the suggested on here How to log users off automatically after a period of inactivity?

<?php
namespace MyProject\UserBundle\EventListener;

use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;


class UserInactivityListener
{

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

    /**
     * user will be logged out after 30 minutes of inactivity
     * 
     * @param FilterControllerEvent $event
     * @return type
     */
    public function onKernelController(FilterControllerEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST != $event-  >getRequestType()) {
            return;
        }

        if ($this->maxIdleTime > 0) {
            try {
                $this->session->start();
                $lapse = time() - $this->session->getMetadataBag()->getLastUsed();
                $isFullyAuthenticated = $this->securityContext->isGranted('IS_AUTHENTICATED_FULLY');

                if (($lapse > $this->maxIdleTime) && $isFullyAuthenticated == true) {
                    $this->securityContext->setToken(null);
                    $url = $this->router->generate('fos_user_security_login');

                    $event->setController(function() use ($url) {
                        return new RedirectResponse($url);

                    });
                }
            } catch (\Exception $ex) {
                return;
            }
        }
    }
}

The problem is that this event will be triggered and the redirect will happen only when the user tries to load anything in the app after his idle time. What I want is for the app to be automatically redirected to the sign up page without any interaction from the user.

I came accross this suggestion to use a refresh meta tag How to auto redirect a user in Symfony after a session time out?, but was wondering if there's another and better way to fire a refresh event every now and then?

Community
  • 1
  • 1
Nat Naydenova
  • 771
  • 2
  • 12
  • 30

1 Answers1

1

Meta refresh is fine if periodic page reloads won't annoy your users. It's probably the most reliable. You could also implement a JavaScript/jQuery snippet like so that pings the server repeatedly:

setTimeout(checkIdleTime, 2000);

In this case every 2000 milliseconds or every two seconds.

function checkIdleTime() {
    $.get('/idle', function()) {
        // If HTTP_OK response, do nothing, otherwise handle error
    }
}

Map the /idle URL to an action that checks "idleness". The action would have to ignore requests to itself of course. Return success if not idle, otherwise forcible logout the user and return some kind of error. Handle the error in the jQuery response; probably a simple redirect will do: window.location.href = '/login';

Check out the FOSJsRoutingBundle to elegantly use Symfony routes from jQuery so you don't have to hardcode URLs.

nurikabe
  • 3,802
  • 2
  • 31
  • 39