Ievads Zend_Auth
Posted on December 9th, 2007 in No Comments »
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