This method is rather brute-force, but it works reasonably well. First, in the bootstrap file, I started a session (this is a best practice anyway):
Code:
<?php
// ...
// Start up a session
require_once 'Zend/Session.php';
Zend_Session::start();
// ...
I created a LoginController.php separate from the other controllers. In that controller, I added this code (using a session namespace to track timeouts, as well as the user's current location):
Code:
<?php
// LoginController.php - Controls application login/logout
class LoginController extends Zend_Controller_Action
{
// Application login function. Runs under the URL http://app/Login/login.
function loginAction()
{
// ... do the login stuff ...
// .. at the point of a successful login ...
if (Zend_Auth::getInstance()->hasIdentity()) {
$authNamespace = new Zend_Session_Namespace('auth');
// timeout is 20 minutes (1200 seconds)
$authNamespace->timeout = time() + 1200;
// If possible, redirect to the page we came from (see the
// preDispatch routine). Otherwise, go to the main index page.
if (isset($authNamespace->requestUri)) {
$this->_redirect($authNamespace->requestUri);
} else {
$this->_redirect('/');
}
}
}
// ...
In all the other controllers, I added a preDispatch() function, which is a hook provided by Zend to perform non-standard functions:
Code:
<?php
// IndexController.php (or any other controller other than LoginController)
class IndexController extends Zend_Controller_Action
{
function preDispatch()
{
$authNamespace = new Zend_Session_Namespace('auth');
// clear the identity of a user who has not accessed a controller for
// longer than a timeout period.
if (isset($authNamespace->timeout) && time() > $authNamespace->timeout) {
Zend_Auth::getInstance()->clearIdentity();
} else {
// User is still active - update the timeout time.
$authNamespace->timeout = time() + 1200;
// Store the request URI so that an authentication after a timeout
// can be directed back to the pre-timeout display. The base URL needs to
// be stripped off of the request URI to function properly.
$authNamespace->requestUri = substr($this->_request->getRequestUri(),
strlen(Zend_Controller_Front::getInstance()->getBaseUrl()));
}
// If the user has no identity here, there has either been a time out or the user has
// not logged in yet.
if (!Zend_Auth::getInstance()->hasIdentity()) {
$this->_redirect('/Login/login');
}
}
// ...
There is one downside to this code: after a timeout re-authentication, control returns back to where the user was at timeout (i.e., it does not follow the current request). To me, this is a fairly minor problem.
This code seems to work fine on these configurations:
Zend Framework v1.5.2 on Linux or OS-X
PHP v5.2.6 on Linux or OS-X
Apache v2.2.9 on Linux or OS-X
Firefox v3.0 on Linux
Konqueror v3.5.7 on Linux
Firefox v2.0.0.14 on OS-X
Safari v3.1.1 on OS-X