Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zend Framework Automatic Logout after inactivity

I'm working on an application that houses several sub applications and I'd like to implement an auto logout after 30 minutes of inactivity. I have an AuthController with login and logout actions mapped to custom /login and /logout routes using the Bootstrap.php as well as a front controller plugin that looks like this:

class Plugin_SessionTrack extends Zend_Controller_Plugin_Abstract {

    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {  

        $employeeSession = new Zend_Session_Namespace('employeeSession');
        $employeeSession->setExpirationSeconds(10);

    }
}

I'm new to PHP and Zend, what exactly is happening to the session after 10 seconds? I have it set low for testing. What I'd like to have happen is if the time of the last request through the front controller plugin was greater than 30 minutes ago, destroy the session and log the user out and redirect them to /login.

I can see obviously that I'm not tracking the time of the last request but my hope was that the setExpirationSeconds would be refreshed each time the user has a request come through this preDispatch method.

Maybe a cookie needs used? I don't need to actually initiate a logout action, it can just be handled the next time the user makes a request, if they've not done anything in the last half hour the session is destroyed and they're logged out, meaning if I walk away for 45 minutes my screen still looks the same but if I click a link or try and submit a form I had up it sends me to /login. I can worry about some type of JS countdown warning later.

Edit: Here's my bootstrap if anyone wants to see it:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    /**
     * Custom routes:
     * 
     * /login
     * /logout
     */
    protected function _initRoutes()
    {

        $router = Zend_Controller_Front::getInstance()->getRouter();

        $loginRoute = new Zend_Controller_Router_Route('login', array('controller' => 'auth', 'action' => 'login'));

        $logoutRoute = new Zend_Controller_Router_Route('logout', array('controller' => 'auth', 'action' => 'logout'));

        $routesArray = array('login' => $loginRoute, 'logout' => $logoutRoute);

        $router->addRoutes($routesArray);

    }

    protected function _initPlugins()
    {

        $frontController = Zend_Controller_Front::getInstance();
        $frontController->registerPlugin(new Plugin_SessionTrack());

    }
}
like image 771
Caley Woods Avatar asked Feb 18 '12 22:02

Caley Woods


1 Answers

When you call Zend_Session::setExpirationSeconds(10), nothing is actually happening to the session after 10 seconds time per se.

This call causes Zend_Session to store an internal value marking that session namespace for expiration at time() + $seconds from the time the call is made. Each time a Zend_Session starts, it checks to see if any session data is marked for expiration, and if so proceeds to check to see if the expiration time or hop count has passed. If that is the case, then the session data in question is unset at initialization, and is therefore no longer accessible by your application.

If you make this call at the beginning of every request, it should continue to prolong the life of the session by that many seconds on each page load.

Keep in mind that if the session settings in php.ini are set to expire the session after 15 minutes, setting a namespace to expire after 60 minutes will not override PHP's session lifetime of 15 minutes. You can make such adjustments to PHP's session directives in your application.ini file.

Setting an expiration on the namespace also has the advantage of automatically removing some session data without having to destroy the entire session.

I don't know the specifics of your application, but you could use the plugin to check and see if they are logged out and forward the request to your login page. You could check for a valid login after creating the namespace, but you also would want to make sure that the current request wasn't a login attempt. Or you could just defer checking for valid login in the plugin and let your ACL handle that later at the controller level.

You may also want to look into Zend_Auth which you can use to persist an identity in the session. The identity can be anything from a simple boolean value indicating if they are logged in, to a full blown user object that implements Zend_Acl_Role_Interface. Zend Auth is also easily extended so you can have multiple Zend_Auth sessions active at the same time by using different namespaces for each instance, and could have your custom auth class set different time limits on different session namespaces.

I hope that helps answer your question, feel free to comment if you have questions on what I said.

EDIT:

I tested the following code and it successfully expired my Zend_Auth identity after the set time. I tested it low with 60 seconds and after waiting 60 seconds to load the page, I no longer had and identity and was "logged out". You could add this to your session track plugin.

<?php
$auth = Zend_Auth::getInstance();

if ($auth->hasIdentity()) { // user is logged in
    // get an instance of Zend_Session_Namespace used by Zend_Auth
    $authns = new Zend_Session_Namespace($auth->getStorage()->getNamespace());

    // set an expiration on the Zend_Auth namespace where identity is held
    $authns->setExpirationSeconds(60 * 30);  // expire auth storage after 30 min
}
like image 58
drew010 Avatar answered Oct 26 '22 09:10

drew010