The Authentication Class
Sunday, November 21, 2010

I prefer to encapsulate the code for logging in and out in a class. In the example I am using for this series of posts, the class is called Application_Model_Login. We have already seen in this post how it is used in the Login Controller.

The class has following methods and member variables:

class Application_Model_Login
{
  private $_dbAdapter = null;
 
  private $_log = null;
 
  public function __construct($dbAdapter = null, $log = null)
  {
    // TODO: Insert construction code here
  }
 
  public function login($username, $password)
  {
    // TODO: Insert login code here
  }
 
  public function logout()
  {
    // TODO: Insert logout code here
  }
}

When using the class, we pass the constructor references to the database adapter and log objects to use; these are stored in the appropriate member variables:

  public function __construct($dbAdapter = null, $log = null)
  {
    $this->_dbAdapter = $dbAdapter;
    $this->_log = $log;
  }

The login method receives the username and password from the calling function:

  public function login($username, $password)
  {

The database adapter must be set, otherwise the class cannot authenticate against the database:

    // Check that the database adapter has been set
    if (null === $this->_dbAdapter)
    {
      if (null !== $this->_log)
        $this->_log->crit('Database adapter not specified');
 
      return false;
    }

Note that the method uses the logger (if it has been supplied) to record this failure. Also, the method returns false to indicate that the login was unsuccessful.

Next, the method gets the date and time of the login attempt; this will be logged later:

    // Get the date and time of the attempt
    $date = new Zend_Date();

Then, the method gets the global authentication object:

    // Get the authentication object
    $auth = Zend_Auth::getInstance();

Next, the method creates an authentication adapter:

    // Set up the authentication adapter
    $authAdapter = new Zend_Auth_Adapter_DbTable(
      $this->_dbAdapter, 'user', 'username', 'password', 'md5(?)');
    $authAdapter->setIdentity($username);
    $authAdapter->setCredential($password);

The adapter is passed the username and password supplied to the method. In this case, the database is assumed to have a user table, with fields named username and password. Also, the password has been encrypted using MD5.

The method is now ready to authenticate the user, using the global authentication object and the adapter:

    // Attempt to authenticate the user
    $result = $auth->authenticate($authAdapter);

If the attempt is successful, the method now gets the entire row in the database table associated with the user. This information is used to create the identity object. This object is an instance of the class Application_Model_Identity, which we will examine in a subsequent post. This identity is stored in the global authentication object. The application will be able to determine whether the user is logged in by the existance of the identity.

   // Check the result of the attempt
    if ($result->isValid())
    {
      // Get the result row object
      $resultRow = $authAdapter->getResultRowObject();
 
      // Create the identity object
      $identity = new Application_Model_Identity($resultRow, 
$this->_dbAdapter, $this->_log);
 
      // Store it in the current session
      $auth->getStorage()->write($identity);

The method uses the logger (if it has been supplied) to record this success, including the date of the attempt:

      if (null !== $this->_log)
      {
        // Log the successful login
        $notice = sprintf('Successful login from %s by %s at %s',
          $_SERVER['REMOTE_ADDR'], $username, $date->toString());
        $this->_log->notice($notice);
      }

Finally, the method returns true, to indicate that the login succeded:

      return true;
    }

If the login attempt fails, the method uses the logger (if it has been supplied) to record this failure, including the date of the attempt:

    else
    {
      if (null !== $this->_log)
      {
        // Log the failed login attempt
        $warn = sprintf(
          'Failed login attempt (invalid username/password) from %s by %s at %s',
          $_SERVER['REMOTE_ADDR'], $username, $date->toString());
        $this->_log->warn($warn);
      }

It then returns false, to indicate that the login failed:

      return false;
    }
  }

The logout function is quite simple. We get the authentication object, then clear any identity stored in it:

  public function logout()
  {
    // Get the authentication object
    $auth = Zend_Auth::getInstance();
 
    // Clear the user identity to log out
    $auth->clearIdentity();
  }

The application will now regard the user as being logged out.

Posted by James at 7:07 pm   4 comments

4 Responses to “The Authentication Class”

  1. [...] Identity Class Thursday, November 25, 2010 In my previous post about creating an authentication class, I made use of another class, called Application_Model_Identity, to store the details of the user, [...]

  2. [...] Access Control List Class Thursday, December 2, 2010 In a previous post, I discussed the creation of an Authentication class. In the following post, I discussed the creation of an Identity class. In this post I shall look at [...]

  3. Humberto Borba says:

    Hi,

    I have a question about logout function.
    Whats happen when user close the browser?
    How to log this action?

    Thanks!

  4. James says:

    An interesting question.

    (1) When the user closes the browser, the current session ends, so when the user restarts the browser, he or she is no longer logged in.

    (2) To log the user closing the browser, you would have to initiate this on the client side, i.e. using JavaScript from within the web page. However, there are a couple of problems with this:

    (a) My understanding is that there is no reliable way to determine that the user has closed the browser, because the relevant event onunload could also occur when you navigate to another page.

    (b) Also, the user may have disabled JavaScript.

Leave a Reply