Autors Rob Allen, www.akrabat.com
Dokumenta versija 1.0.8
Autortiesības © 2007.
Latviešu valodā tulkojis Ingus Rūķis, www.webtech.lv

Šī pamācība ir paredzēta, lai dotu pavisam vienkāršu ieskatu Zend Framework Zend_Auth komponenta lietošanā. Šajā pamācībā tiek turpināta Zend Framework ievada iesāktā projekta izstrāde.

Ievērojiet! Šī pamācība ir testēta ar Zend Framework versijām 1.0.0 un 1.0.1. Tas nozīmē, ka ir ļoti liela varbūtība, ka šajā pamācībā esošie piemēri darbosies arī uz jaunākām šī ietvara versijām, taču var rasties problēmas ar vecākām ietvara versijām.

Priekšvārds

Autentifikācijas modelis, kuru mēs izmantosim lieto PHP sesijas. Pirms sākt darbu ar pamācību, lūdzams pārliecināties par to, lai jūsu PHP instalācijai būtu sesiju atbalsts un session.save_path direktorijai, kas norādīta php.ini failā ir jābūt rakstīšanas tiesībām PHP procesam. Pretējā gadījumā jūs varat saņemt visai nepatīkamus kļūdas paziņojumus.

Autentifikācija

Šajā pamācībā ar autentifikāciju sapratīsim procesu, kurā kāds lietotājs tiek autentificēts pirms darba ar aplikāciju. Mēs modificēsim CD uzskaites aplikāciju, kuru izveidojām iepriekšējā pamācībā “Ievads Zend Framework“, lai atļautu piekļūt jebkurai aplikācijas daļai tikai pēc tam, kad lietotājs ir autentificējies.

Vispārīgi skatoties, lietas, kas mums ir jāizdara, ir šādas:

  • Izveidot lietotāju datubāzi (un pievienot tajā ierakstus)
  • Izveidot autentifikācijas formu.
  • Izveidot kontrolieri, kas saturētu darbības lietotāja autentificēšanai un iziešanai no sistēmas
  • Izmainīt lapas kājeni, lai ļautu iziet no sistēmas
  • Nodrošināt, ka lietotājs ir autorizējies, pirms tas var piekļūt pie jebkuras no aplikācijas daļām.

Lietotāju tabula

Pirmā lieta, kas mums ir vajadzīga ir lietotāju tabula. Tai nav jābūt sarežģītai, tāpēc tās shēma izskatās šādi:

Lauka nosaukums Tips Null? Piezīmes
id Integer No Primary key, auto increment
username Varchar(50) No Unique key
password Varchar(50) No  
real_name Varchar(100) No  

Lietojot MySQL, SQL teikums izskatās šādi:

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

Tāpat mums ir vajadzīgs arī lietotājs, kas var autorizēties sistēmā:

INSERT INTO users (id, username, password, real_name)
VALUES (1, 'rob', 's0mep4ssw0rd', 'Rob Allen'); 

Izpildiet šos teikumus MySQL klienta aplikācijā, piemēram, phpMyAdmin vai parastajā MySQL komandrindas klientā. (Protams, jums vajadzētu izvēlēties arī labāku lietotāja vārdu un paroli!)

Sāknēšanas faila izmaiņas

Lai veiktu uzskaiti par to, ka lietotājs ir autentificējies sistēmā, mēs lietosim sesijas. Zend Framework piedāvā Zend_Session_Namespace, kas piedāvā labu objektorientētu saskarni ar sesiju.

Izmaiņas index.php failā ir šādas:

zf-tutorial/index.php:

...
Zend_Loader::loadClass('Zend_Db_Table');
Zend_Loader::loadClass('Zend_Debug');
Zend_Loader::loadClass('Zend_Auth');

// load configuration
...

un

...
// setup database
$db = Zend_Db::factory($config->db->adapter,
        $config->db->config->toArray());
Zend_Db_Table::setDefaultAdapter($db);
Zend_Registry::set('db', $db);

// setup controller
$frontController = Zend_Controller_Front::getInstance();
...

Patiesībā viss, kas mums šeit bija jāizdara, bija jāpārliecinās, ka esam ielādējuši Zend_Auth klasi un piereģistrējuši datubāzes adapteri reģistrā. Mēs uzglabājam to reģistrā, jo mums tas ir nepieciešams vēlāk, kad veiksim lietotāja autentifikāciju.

Autentifikācijas kontrolieris

Mums ir nepieciešams kontrolieris, kas saturētu autentifikācijas un darba beigšanas darbības. Būtu prātīgi to nosaukt par AuthController.

Mēs sāksim ar pamatiem no IndexController:

zf-tutorial/application/controllers/AuthController.php:

<?php
class AuthController extends Zend_Controller_Action
{
    function init()
    {
        $this->initView();
        $this->view->baseUrl = $this->_request->getBaseUrl();
    }

    function indexAction()
    {
        $this->_redirect('/');
    }
} 

Mēs izveidojam init() metodi, lai tiktu inicializēts baseUrl un piešķirts tam. Mēs tāpat veidojam arī indexAction, kuru pieprasa Zend_Controller_Action. Mums patiesībā nav nepieciešama šī indexAction(), jo mēs lietojam loginAction() un logoutAction(). Tādējādi mēs vienkārši pārsūtam atpakaļ uz noklusēto darbību, ja kāds mēģina atvērt lapu auth/index.

Autentifikācija

Lai lietotājs varētu autentificēties sistēmā, mums ir nepieciešama forma, tādējādi tā darbosies līdzīgi, kā citas formas mūsu IndexController. Formas šablons atradīsies views/scripts/auth/login.phtml un kods atradīsies AuthController::loginAction(). Forma ir ļoti vienkārša, kurā jāaizpilda tikai divi lauki: lietotāja vārds un parole:

zf-tutorial/application/views/scripts/auth/login.phtml:

<?php echo $this->render('header.phtml'); ?>
<h1><?php echo $this->escape($this->title); ?></h1>

<?php if(!empty($this->message)) :?>
<div id="message">
<?php echo $this->escape($this->message);?>
</div>
<?php endif; ?>

<form action="<?php echo $this->baseUrl ?>/auth/login" method="post">
<div>
    <label for="username">Username</label>
    <input type="text" name="username" value=""/>
</div>
<div>
    <label for="password">Password</label>
    <input type="password" name="password" value=""/>
</div>
<div id="formbutton">
<input type="submit" name="login" value="Login" />
</div>
</form>

<?php echo $this->render('footer.phtml'); ?> 

Šablons veido header.phtml un footer.phtml augšā un apakšā kā parasti. Ievērojiet, ka mēs parādām $this -> message tikai tad, ja tā nav tukša. Tas tiek izmantots, lai parādītu lietotājiem paziņojumu gadījumā, ja lietotājs ir ievadījis nepareizu lietotāja vārdu vai paroli. Pārējā šablona daļa ir vienkārši pati autentifikācijas forma.

Tagad, kad mums ir forma, mums ir jāizveido kontroliera darbība, kas to darbinās. To mēs pievienojam AuthController.php:

zf-tutorial/application/controllers/AuthController.php:

class AuthController extends Zend_Controller_Action
{
...
    function loginAction()
    {
        $this->view->message = '';
        $this->view->title = "Log in";
    }
} 

Sākotnēji viss, kas mums ir vajadzīgs, ir uzstādīt nosaukumu un tukšu message mainīgo, tad parādīt formu. Ja jūs atvērsiet http://localhost/zf-tutorial/auth/login, tad jums vajadzētu redzēt autentifikācijas formu.

Nākamais solis ir formas apstrāde pēc tam, kad ir nosūtīti tās dati. Lai to izdarītu, mēs izmantojam to pašu triku, kādu izmantojām datu pievienošanas un rediģēšanas formās IndexController un veicam datu apstrādi tikai tad, ja dati tiek iesūtīti ar post metodi. Izmainiet loginAction, kuru mēs tikko izveidojām:

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');
                $db = Zend_Registry::get('db');
                $authAdapter = new Zend_Auth_Adapter_DbTable($db);
                $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";
    }
} 

Tā kā šeit notiek diezgan daudzas lietas uzreiz kopā, iziesim tam cauri pa daļām:

// 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 {

Kā jau pierasts, mēs uzstādām filtru un tad tiekam pie lietotāja vārda un paroles no POST datiem. Ievērojiet, ka mēs lietojam Request getPost() funkciju, kas veiks isset() pārbaudi mūsu vietā un atgriezīs tukšu teksta virkni gadījumā, ja tāda vērtība POST datos nav uzstādīta. Ja lietotāja vārds ir tukšs, tad nav nekādas jēgas mēģināt autentificēt lietotāju (Zend_Auth tāpat atgriezīs kļūdas paziņojumu, ja mēs mēģināsim), tāpēc mēs veicam šo pārbaudi un paziņojam par to lietotājam.

// setup Zend_Auth adapter for a database table
Zend_Loader::loadClass('Zend_Auth_Adapter_DbTable');
$db = Zend_Registry::get('db');
$authAdapter = new Zend_Auth_Adapter_DbTable($db);
$authAdapter->setTableName('users');
$authAdapter->setIdentityColumn('username');
$authAdapter->setCredentialColumn('password');

Zend_Auth izmanto adapteru sistēmu, kas ļauj programmētājam izmantot jebkuru skaitu sistēmu, lai tieši autentificētu lietotāju. Mēs lietosim datubāzes tabulu un izmantosim Zend_Auth_Adapter_DbTable. Lai uzstādītu adapteri, programmētājam ir jānorāda lauki, kurus izmantot.

// Set the input credential values to authenticate against
$authAdapter->setIdentity($username);
$authAdapter->setCredential($password);

Mums ir jānodod tieši tas pats lietotāja vārds un parole, kurus lietotājs ir ievadījis formā.

// do the authentication
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);

Lai veiktu tieši autentifikācijas darbību, mēs izsaucam authenticate() funkciju no Zend_Auth. Tas nodrošina, ka autentifikācijas rezultāti automātiski tiek saglabāti sesijā.

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('/'); 

Veiksmīgas autentifikācijas gadījumā mēs saglabājam pilnu datubāzes ierakstu (izņemot paroli) Zend_Auth singleton šablonā. Tas nodrošina, ka mēs varam ērti tikt pie lietotāja vārda un parādīt to lapas kājenē.

} else {
        // failure: clear database row from session
        $this->view->message = 'Login failed.';
    }
} 

Autentifikācijas kļūdas gadījumā, mēs uzstādām message mainīgo, lai lietotājs zinātu, kas ir noticis.

Autentifikācijas process lietotāja ieiešanai sistēmā ir pabeigts.

Darba beigšana ar sistēmu

Darba beigšana ar sistēmu ir daudz vienkāršāka, nekā lietotāja autentificēšana, jo viss, kas mums ir jāizdara, ir jāpasaka Zend_Auth singleton šablonam, lai tiktu notīrīti tajā esošie dati. Tas tiek darīts ar jaunu darbību logoutAction AuthController kodā. Tādējādi, ja mēs aizejam uz http://localhost/zf-tutorial/auth/logout, lietotājs pārtrauc darbu ar sistēmu:

zf-tutorial/application/controllers/AuthController.php:

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

logoutAction() funkcija ir tik vienkārša, pat grūti iedomāties, ko lai vēl tur paskaidro.

Tagad mums ir nepieciešams lietotājam piedāvāt saiti, lai tie varētu beigt darbu ar aplikāciju. Visvienkāršāk to ir izdarīt kājenē. Tāpat mēs norādīsim arī šī lietotāja vārdu, lai lietotāji varētu būt pārliecināti, ka tie ir viņi, kas darbojas ar sistēmu. Lietotāju vārdi tiek glabāti real_name laukā lietotāju tabulā un ar tādu pašu parametru tie ir pieejami Zend_Auth instancē. Pirmā lieta, ko darīt ir to ievietot skatā, to mēs varam izdarīt init() funkcijā IndexController kontrolierī:

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();
    }
...
} 

Ir skaidri redzams, ka Zend_Auth ir singleton, citādi mēs to saglabātu reģistrā.

Tagad mums ir jāpievieno mazliet HTML savam footer.phtml šablonam:

zf-tutorial/application/views/scripts/footer.phtml:

<?php if($this->user) : ?>
<p id="logged-in">Logged in as <?php
    echo $this->escape($this->user->real_name);?>.
<a href="<?php echo $this->baseUrl ?>/auth/logout">Logout</a></p>
<?php endif; ?>
</div>
</body>
</html>

Šim HTML ir jābūt pietiekami pazīstamam, jo te nav nekādu jaunu lietu. Mēs izmantojam escape(), lai nodrošinātu, ka lietotāja reālais vārds tiek korekti parādīts un mēs lietojam baseUrl, lai uzstādītu href pareizu saites adresi.

Tas ir viss, kas ir nepieciešams, lai lietotājs varētu beigt darbu.

Darbību aizsargāšana

Viss, kas ir atlicis ir nodrošināties pret to, ka kāda no darbībām ir pieejama bez autentifikācijas. Lai to panāktu, mums ir jāpievieno nedaudz koda preDispatch() funkcijai mūsu IndexController.

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');
        }
    }
...
}

preDispatch tiek izsaukts pirms visām darbībām kontrolierī. Mēs tiekam pie Zend_Auth instances un pēc tam ar tās funkciju hasIdentity() mēs varam pārbaudīt, vai lietotājs ir autentificējies sistēmā. Ja lietotājs nav autentificējies, tad mēs to pārsūtām uz auth/login darbību.

Tas arī viss!

Noslēgums

Ar to arī mēs varam noslēgt savu īso apskatu par Zend_Auth pielietojumu MVC aplikācijā. Ir pavisam skaidrs, ka ar Zend_Auth palīdzību ir iespējams paveikt daudz vairāk un ir daudzi veidi, kā uzlabot koda darbību, kas varētu būt nepieciešams, ja ir vairāki kontrolieri, kas ir jāaizsargā. Ievērojiet, ka mēs neesam detalizēti apskatījuši pašu autentifikācijas procesu, jo to nodrošina Zend_Acl komponenti. Zend_Acl tiek lietots kopā ar Zend_Auth gadījumos, kad ir nepieciešams nodrošināt dažādus pieejas līmeņus darbībām vai datiem, taču tā jau ir atsevišķas pamācības tēma.

Cerams, ka pamācība bija informatīva un interesanta. Ja atrodat kādas tehniska rakstura kļūdas, lūdzu ziņot angļu valodā uz rob@akrabat.com. Gadījumā, ja tiek atrastas kādas tulkojuma neprecizitātes, tad varat droši rakstīt uz ingus@webtech.lv