Introduction to Zend_Auth

Original author: Rob Allen
  • Transfer
The article provides an overview of the features of the component Zend_Auth, which gives an overview of the implementation of user authorization in applications based on Zend Framework. As a basis for the given examples, the materials of the article "Introduction to Zend Framework" were used . Examples were tested on Zend Framework versions 0.9, 0.9.1 and 0.9.2, and most likely will work with later versions, but not with earlier ones.

Author: Rob Alen, http://akrabat.com
Original: http://akrabat.com/zend-auth-tutorial
Translation: Alexander Musaev, http://paradigm.ru

Printable PDF: http: // archive .paradigm.ru / zend_auth.pdf

Before you start

The implementation of the user authentication mechanism, which we will use in our examples, is based on PHP sessions. Make sure that the session.save_path parameter in your is php.iniset to the directory accessible to the web server for writing.

Authentication

Authentication or authentication is the procedure for verifying the conformity of the subject and who he is trying to impersonate using some unique information. This procedure should be distinguished from identification (recognition of the subject of information interaction) and authorization (verification of access rights to system resources).

In the context of web applications, authentication usually means checking whether a user matches his account on a web server with a name (“login”) and password. As an example of the implementation of such a mechanism based on the Zend Framework, we will supplement the CD-ROM base with a similar check (the web application implemented in the article “Introduction to Zend Framework”).

For this we need:
  1. create a table in the database for users (and add a new account to it);
  2. create a login form;
  3. implement a controller containing actions for entering and exiting;
  4. add the ability to log out to the general fragment of page templates;
  5. add verification that the user is logged in before allowing him to perform any action.

Users table

The first thing we need is a table in the database for storing user accounts. Her scheme will look like this:

FieldA typeNull?Field options
idIntegerNoPrimary key, Autoincrement
usernameVarchar (50)NoUnique key
passwordVarchar (50)No -
real_nameVarchar (100)No-


When using MySQL, such a table can be created with the following query:
CREATE TABLE users (
    id INT(11) NOT NULL AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL,
    real_name VARCHAR(100) NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY username (username)
)

We will need to add a test user account to it:
INSERT INTO users (id, username, password, real_name)
    VALUES (1, 'rob', 'rob', 'Rob Allen');

Run these SQL queries using any MySQL client program. The username and password can be changed to any other values ​​if desired.

Boot file

In order to be able to track the registration of users in the system (entry and exit), we need to use the mechanism of PHP-sessions. For convenient work with it, the Zend Framework provides a special class Zend_Session_Namespace.

We will need to make the following changes to the bootstrap file:

zf-tutorial/index.php:
...
Zend_Loader::loadClass('Zend_Db_Table');
Zend_Loader::loadClass('Zend_Debug');
Zend_Loader::loadClass('Zend_Auth');
// load configuration
...
// setup database
$dbAdapter = Zend_Db::factory($config->db->adapter,
    $config->db->config->asArray());
Zend_Db_Table::setDefaultAdapter($dbAdapter);
Zend_Registry::set('dbAdapter', $dbAdapter);
// setup controller
$frontController = Zend_Controller_Front::getInstance();
...

All you need to do here is to make sure the class is Zend_Authconnected and the database adapter is dbAdapterregistered. This adapter will be stored in the registry, because later you will need to have access to it from the authorization controller.

Authorization controller

In order to group the input and output actions, we need a special controller. It would be logical to ask him a name AuthController. Let's start its implementation with the constructor and define the default action ( indexAction()):

zf-tutorial/application/controllers/AuthController.php:
class AuthController extends Zend_Controller_Action
{
    function init()
    {
        $this->initView();
        $this->view->baseUrl = $this->_request->getBaseUrl();
    }
    function indexAction()
    {
        $this->_redirect('/');
    }
}

In the constructor of the controller class, the view is initialized and the value of the variable is assigned baseUrl. In addition to the constructor, an action is defined in the class indexAction(), which is a mandatory requirement for all heirs Zend_Controller_Action. Given that we are going to use only loginAction()and logoutAction(), we don’t need a default action, therefore we will redirect the user from the corresponding URL to the main page of the site.

entrance

In order to enter the system, you need a special form. A logincontroller action AuthControllerwill interact with it in the same way that actions IndexControllerwork with their forms. The form template is located in the file views/scripts/auth/login.phtml, and the data from it will be processed by the method AuthController::loginAction().

The login form is quite simple and contains only two fields - for the username and password.

zf-tutorial/application/views/scripts/auth/login.phtml:
render('header.phtml'); ?>

escape($this->title); ?>


message)) :?>

escape($this->message);?>




    
    


    
    





render('footer.phtml'); ?>

The template displays header.phtmlboth footer.phtmlat the beginning and at the end of the page, respectively. Note that a message from a variable $this→messageis displayed only if its value is not empty. This variable is used if there were errors during the login and the user needs to report it. The rest of the template is the login form itself.

Now that our form is ready, we can move on to creating a controller to work with it.

zf-tutorial/application/controllers/AuthController.php:
class AuthController extends Zend_Controller_Action
{
    ...
    function loginAction()
    {
        $this->view->message = '';
        $this->view->title = "Log in";
        $this->render();
    }
}

To display the form, you need to specify its title and message body, after which the form can be seen by clicking on the URL http://zf-tutorial/auth/login. The question arises, how, in this case, process the data sent from it? To do this, we use the same method that was used in the case of forms for editing and adding entries to IndexController. That is, data processing will be performed only if the method of accessing the server is POST. Otherwise, the action loginwill simply produce a form. The necessary changes loginAction()are shown below.

zf-tutorial/application/controllers/AuthController.php:
class AuthController extends Zend_Controller_Action
{
    ...
    function loginAction()
    {
        $this->view->message = '';
        if ($this->_request->isPost()) {
            // collect the data from the user
            Zend_Loader::loadClass('Zend_Filter_StripTags');
            $f = new Zend_Filter_StripTags();
            $username = $f->filter($this->_request->getPost('username'));
            $password = $f->filter($this->_request->
            getPost('password'));
            if (empty($username)) {
                $this->view->message = 'Please provide a username.';
            } else {
                // setup Zend_Auth adapter for a database table
                Zend_Loader::loadClass('Zend_Auth_Adapter_DbTable');
                $dbAdapter = Zend_Registry::get('dbAdapter');
                $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
                $authAdapter->setTableName('users');
                $authAdapter->setIdentityColumn('username');
                $authAdapter->setCredentialColumn('password');
                // Set the input credential values
                // to authenticate against
                $authAdapter->setIdentity($username);
                $authAdapter->setCredential($password);
                // do the authentication
                $auth = Zend_Auth::getInstance();
                $result = $auth->authenticate($authAdapter);
                if ($result->isValid()) {
                    // success: store database row to auth's storage
                    // system. (Not the password though!)
                    $data = $authAdapter->getResultRowObject(null, 'password');
                    $auth->getStorage()->write($data);
                    $this->_redirect('/');
                } else {
                    // failure: clear database row from session
                    $this->view->message = 'Login failed.';
                }
            }
        }
        $this->view->title = "Log in";
        $this->render();
    }
}

Consider the above code step by step:
// collect the data from the user
Zend_Loader::loadClass('Zend_Filter_StripTags');
$f = new Zend_Filter_StripTags();
$username = $f->filter($this->_request->getPost('username'));
$password = $f->filter($this->_request->getPost('password'));

if (empty($username)) {
    $this->view->message = 'Please provide a username.';
} else {
    ...

Here, as usual, we extract the username and password from the POST array and process their values ​​with an HTML filter. The function used for this getPost()automatically checks for the presence of variables specified in its parameter and, if none are found in POST, returns an empty value.

The authentication process continues only if the username is specified. If empty, an attempt to authenticate through Zend_Authwould raise an exception.
// setup Zend_Auth adapter for a database table
Zend_Loader::loadClass('Zend_Auth_Adapter_DbTable');
$dbAdapter = Zend_Registry::get('dbAdapter');
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter->setTableName('users');
$authAdapter->setIdentityColumn('username');
$authAdapter->setCredentialColumn('password');

To work with authorization data Zend_Auth, the adapter subsystem is used. Such adapters provide a unified interface to heterogeneous data stores, such as relational databases, LDAP, or simple files. In our example, the database will be used for this purpose, so the adapter is selected Zend_Auth_Adapter_DbTable. In order to initialize it, it is necessary to set the database parameters (the name of the user table and the names of its fields).
// Set the input credential values to authenticate against
$authAdapter->setIdentity($username);
$authAdapter->setCredential($password);

We must also pass to the adapter the exact values ​​of the username and password that were entered into the form.
// do the authentication
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);

In order to perform the authentication procedure itself, a authenticate()class method is called Zend_Auth. In this case, the authentication result is automatically saved in the session.
if ($result->isValid()) {
    // success : store database row to auth's storage
    // system. (not the password though!)
    $data = $authAdapter->getResultRowObject(null,
        'password');
    $auth->getStorage()->write($data);
    $this->_redirect('/');

In case the authentication was successful, the user account from the database will be completely saved inside the singleton Zend_Auth(with the exception of the password, of course).
    } else {
        // failure: clear database row from session
        $this->view->message = 'Login failed.';
    }
}

In the event that the verification of the username and password did not pass, we inform inform the user about this through a variable message. This completes the authentication process for logging in.

Exit

Logging out is much easier than logging in. All that is required is to clear the data inside the singleton Zend_Auth. This is implemented in the action of the logoutAction()controller AuthController. Thus, to exit, you just need to go to the URL http://zftutorial/auth/logout.

zf-tutorial/application/controllers/AuthController.php:
class AuthController extends Zend_Controller_Action
{
    ...
    function logoutAction()
    {
        Zend_Auth::getInstance()->clearIdentity();
        $this->_redirect('/');
    }
}

The function logoutAction()is so trivial that there is absolutely nothing to comment on.

We will need to provide the user with a special link, by clicking on which he could exit the web application. The easiest way to do it is inside the template footer. In addition, we will tell the user his name so that he is sure that the authorization was successful. User names are stored in the field of the real_namecorresponding database table, and can be accessed from Zend_Auth. The first thing that needs to be done is to pass this value into a view, which we will do inside the init()controller function IndexController().

zf-tutorial/application/controllers/IndexController.php:
class IndexController extends Zend_Controller_Action
{
    function init()
    {
        $this->initView();
        Zend_Loader::loadClass('Album');
        $this->view->baseUrl = $this->_request->getBaseUrl();
        $this->view->user = Zend_Auth::getInstance()->getIdentity();
    }
    ...
}

It’s very convenient that it Zend_Authis singleton. Otherwise, in this case, it would be necessary to store its contents in the registry.

Now we need to make changes to the file footer.phtml.

zf-tutorial/application/views/footer.phtml:
user) : ?>

Logged in as     echo $this->escape($this->user->real_name);?>.
Logout






The above code does not contain anything fundamentally new. We use escape()to make sure that the username is displayed correctly in the browser. The value of the variable baseUrlis used to correctly form the link.

The logout function is ready.

Action protection

All that remains for us to do is to make sure that no actions will be unavailable before the user logs in.

zf-tutorial/application/controllers/IndexController.php:
class IndexController extends Zend_Controller_Action
{
    ...
    function preDispatch()
    {
        $auth = Zend_Auth::getInstance();
        if (!$auth->hasIdentity()) {
            $this->_redirect('auth/login');
        }
    }
    ...
}

A function with a standard name is preDispatch()automatically called before any action by the controller. Using the hasIdentity()object method Zend_Auth, we check to see if the login is complete. And, if it’s not, redirect the user to auth/login.

This completes the work on authorization.

Conclusion

The given example of the implementation of user authorization functions based on the Zend Framework is quite simple, but you should understand that Zend_Auththere are many more useful features that can be used to protect more complex applications with several controllers. The authorization system implemented in the component was also not affected Zend_Acl. The latter is intended to be used in conjunction with Zend_Authto delimit the levels of user access to actions or data, but this is already a topic for another discussion.

You can send all comments regarding the original article to the author at rob@akrabat.com. Comments on the Russian translation send to musayev@yandex.ru.

Update: an archive with examples of programs from the article can be found on the author’s website:zend_auth-tutorial_104.zip .

Also popular now: