December 29th, 2011 Category: Curso Zend Framework
48 Comments »
En los anteriores capitulos habiamos usado el video como metodo de aprendizaje, hoy habiendo cubierto la parte inicial y basica de Zend Framework, creo que estamos preparados para dejar el video atras, y continuar los capitulos leyendo un poco.
En este capitulo vamos a ver como crear un sistema de login en nuestro proyecto. Nosotros actualmente en nuestro portal de noticias tenemos una pantalla donde publicamos nuestras noticias. Pero actualmente esa pantalla es accesible por cualquier persona.
El objetivo de este capitulo es crear una pantalla de login, y restringir el acceso a la administracion de las noticias solo a las personas que tengan usuario y contraseña.
Lo primero que vamos a hacer es crear un nuevo controller, UsuarioController.php
El codigo de este controller inicialmente sera asi.
class UsuarioController extends Zend_Controller_Action
{
public function init()
{
}
public function loginAction()
{
$form = new Application_Form_Login();
if( $this->getRequest()->isPost() ){
if( $form->isValid( $this->_getAllParams() )) {
// Do something
}
}
$this->view->form = $form;
}
}
Para este controller vamos a tener que crear una vista asi que creamos la carpeta en views/scripts/usuario y agregamos el archivo login.phtml, donde vamos a imprimir el formulario y mostrar un mensaje, el archivo quedaria asi
<div>
<h2>Ingresar al sistema</h2>
<?php echo $this->form ; ?>
</div>
Tambien vamos a necesitar un formulario para poder ingresar usuario y contraseña.
Creamos el archivo en forms/Login.php
Este formulario va a tener un input para el usuario otro para el contraseña, y el boton de submit, el formulario Login.php nos quedaria asi.
class Application_Form_Login extends Zend_Form
{
public function init()
{
$this->addElement(
'text', 'username', array(
'label' => 'Usuario:',
'required' => true
)
);
$this->addElement(
'password', 'password', array(
'label' => 'Contraseña:',
'required' => true
)
);
$this->addElement(
'submit', 'Ingresar', array()
);
}
}
Hasta ahora no vimos nada nuevo, es mas o menos el mismo mecanismo que usamos para crear un nuevo post. Si entramos en la url de nuestro proyecto /usuario/login vamos a ver el formulario de login como aparece en la siguiente imagen.

Ahora que tenemos el codigo vamos a crear una tabla donde se van a guardar todos los usuarios que van a tener permisos al panel de administracion de nuestro proyecto. El sql para crear la tabla es el siguiente.
CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(40) NOT NULL,
`password` char(40) NOT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
INSERT INTO `users` (`username`, `password`) VALUES
('pablo', '7c4a8d09ca3762af61e59520943dc26494f8941b');
Nuestra tabla de usuario es bastante sencilla, por ahora vamos a cumplir con los requerimientos minimos. El hash extraño que se ve es la contraseña “123456″ encriptada con la funcion sha1()
Ahora que ya tenemos un usuario (pablo) y una contraseña (123456), nos falta agregar la logica para que se valide si el usuario existe o no.
Zend Framework nos brinda el componente Zend_Auth el cual a partir de sus Adapters, nos permite validar un usuario y loguearlo en el sistema. La forma de usarlo es bastante simple, Zend Auth entiende identidad y credencial, donde la identidad es el nombre de usuario o mail que vamos a usar para identificar a un usuario dentro del sistema, y la credencia es la contraseña.
Nosotros vamos a usar Zend_Db_Adapter_DbTable el cual se encarga de validar el usuario y contraseña en nuestra base de datos.
El codigo cuando usemos Zend_Auth deberia ser el siguiente.
$authAdapter = new Zend_Auth_Adapter_DbTable();
$authAdapter
->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password');
$authAdapter
->setIdentity('pablo')
->setCredential(sha1('123456'));
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if( $result->isValid() ){
echo "Estamos Logueado!";
}else{
echo "Datos incorrecto";
}
Ahora este codigo vamos a adaptarlo a nuestro controller. Nos quedaria asi
class UsuarioController extends Zend_Controller_Action
{
public function init()
{
}
public function loginAction()
{
$form = new Application_Form_Login();
if( $this->getRequest()->isPost() ){
if( $form->isValid( $this->_getAllParams() )) {
$authAdapter = new Zend_Auth_Adapter_DbTable();
$authAdapter
->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password');
$authAdapter
->setIdentity($form->getValue('username'))
->setCredential(sha1($form->getValue('password')));
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if( $result->isValid() ){
return $this->_redirect('/posts/listar');
}else{
$form->username->addErrorMessage('Datos Incorrectos');
}
}
}
$this->view->form = $form;
}
}
Con este codigo cada vez que nos identifiquemos correctamente nos va a redirigir a /posts/listar donde vamos a mostrar todas las noticias.
Ahora los que nos faltaria agregar es que en cada lugar donde nosotros queramos restringir el acceso, agregar el chequeo si el usuario esta logueado o no, sino esta logueado vamos a redireccionarlo a la pantalla de login.
En cada action que querramos validar esto vamos a agregar el siguiente codigo.
$auth = Zend_Auth::getInstance();
if (! $auth->hasIdentity()) {
return $this->_redirect('/usuarios/login');
}
Notese que en el caso de PostsController, tenemos metodos que son de acceso publico y acceso privado, si llegado el caso tenemos un Controller donde necesitamos que todos los metodos sean de alcance privado, las lineas de arriba podemos escribirlas en el metodo init() de nuestro controller, ese metodo init se va a llamar antes de ejecutar un action de ese controller, y de esta forma evitamos repetir codigo.
Hay otras practicas para mejorar esto pero eso podemos verlo mas adelante.
Ahora que restringimos el acceso, vamos a necesitar la posiblidad de desloguearnos del sistema, para eso vamos agregar un link en nuestro layout.phtml en la parte del menu, que nos redireccione a /usuarios/logout y este es el codigo de nuestro action para desloguarnos.
public function logoutAction()
{
Zend_Auth::getInstance()->clearIdentity();
return $this->_redirect('/usuario/login');
}
Bastante simple, no
, asi es todo con Zend Framework.
Ahora, vamos a dejarlo mas bonito a todo esto, y vamos validar en la vista si el usuario esta logueado, voy a mostrar un link a logout, si esta deslogueado voy a mostrar un link a la pantalla de login. El codigo a agregar en nuestro layout seria el siguiente.
<?php
$auth = Zend_Auth::getInstance();
if ( $auth->hasIdentity()) :
?>
<li>Usuario:<?php echo $auth->getIdentity() ?></li>
<li><a href="/usuario/logout">Logout</a>
<?php else: ?>
<li><a href="/usuario/login/">Login</a>
<?php endif;?>
Y con esto ya somos capaces de agregar un sistema de login en nuestros proyectos usando Zend Framework.
Ver todos los capitulos del curso
Invitame una Cerverza
Comentar
48 Responses
Tambien recorda, que no es una buena practica tener metodos que no sean nombreAction() en los controllers, y menos privates, de ultima llama a los modelos.
private function getAuthAdapter()
{
...
}
dentro del controller, es mejor inyectarlo desde un modelo?? o sea esto esuna funcion particular para partir el codigo.
Cuando abris un controller la idea es que lo unico que veas es metodos Action, no funcionalidades extras. Para eso tenes las librerias y los modelos. Los controllers tienen que ser lo mas escueto posible.
Es un intento de ZF de tener su propio ORM, no me parece mal, salvo lo de getter y setter, creo que el Data Mapper es algo perfecto para usar.
El tema de getter y setter es una pelotudes que se implementa copiando a la gente de Java, totalmente inutil, y totalmente inecesario.
Tenemos magi method, o mejor es usar un toArray, o setFromArray o cosas parecidas. Yo tendria dos capas.
El DbTable que sea como el modelo de hoy en Dia, extendiendo de Zend_Db_Table, y un dataMapper no por cada tabla sino cada vez que lo amerite
Que diferencia hay entre colocar la validacion:
$auth = Zend_Auth::getInstance();
if (! $auth->hasIdentity()) {
return $this->_redirect('/usuarios/login');
}
en preDispatch() y en init() ??
No es mas seguro que este en preDispatch() ?.
Saludos
El metodo init lo ejecuta antes de ejecutar un action, deberia comportarse igual.
Pero podes agregarlo en el PreDispatch tambien, o de alguna forma mas personalizada en el Bootstrap, pero ahi tendrias que trabajar un poquito mas con la logica.
if( $result->isValid() ){
return $this->_redirect('/posts/listar');
}else{
$form->username->addErrorMessage('Datos Incorrectos');
}
No me muestra el error si coloco datos incorrectos, pero cambie la funcion addErrorMessage a addError y si funciona..
Saludos
me despido de usted deseandole exito en todo y ya le considero como un amigo mas porque me ha facilitado sus conocimientos para poder realizar mi tesis,de verdad gracias por su ayuda desinteresada. bueno le deso un Feliz Año Nuevo.
@fredyx007 Gracias, un gusto haber servido. LO de Zend_PDF podemos verlo mas adelante. La verdad es que nunca lo use.
Feliz año nuevo! y gracias!
Una vez mas te agradezco por este curso.
Feliz año nuevo!!! :)
Manito sigo guerriando con la vaina de la edicion de datos, listo me cargan los datos al campo de l form, pero cuando voy a actualizar con algun campo vacion, me genera erro no hace nada,s e supone que el form debe ser validado antes, que tendre mal mano.
@francisco cuando hablo de data mapper me refiero a esto http://martinfowler.com/eaaCatalog/dataMapper.html
El ejemplo que usan el quickstart de la pagina de Zend Framework, te muestra como usar el mapper, y los dbtable.
De antemano Gracios
Por lo que entiendo, se te da acceso a una url especifica en un puerto especifico. Vos deberias usar aglun reproductor flash seguramente para hacer streeming en esa url especifica.
Y claramente podrias embeberla en cualqueir vista del proyecto.
Esto tocando de oido, pero supongo que no es mucho mas que eso.
http://tecnoculto.com/wp-content/uploads/etapas_del_programador-26-06-2008.jpg
Pablo muchas gracias por este tutorial, sigue con tus excelentes contribuciones.
no se
Quisiera que porfavor me ayudaras con un tutorial o clase usando zend_acl y zend_navegation.He encontrado poca informacion acerca de esos componentes zend y ademas están en inglés.
Saludos..
@Alfredo Voy a tratar de agregar lo de Zend Acl para los proximos capitulos
@Nalleli No entendi el problema.
@Jonathan, gracias por el feedback, como le decia a Alfredo en los proximos voy a ver de incluir el tema de ACL
//Esta funcion ponela en el bootstrap..modifica algunos valores por los nombres que les hayas puesto a tus variables de autenticacion..
public function profileLink()
{
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$username = $auth->getStorage()->read('user');
return 'Bienvenido, ' . $username . ' | Logout';
}
return 'Login';
}
//Y despues yo en el layout hice lo siguiente..
Espero que te sirva, saludos!
https://code.google.com/p/midocu/downloads/list
@Nalleli, podes traerlo haciendo una busqueda en el modelo con el username
Podrías darme un ejemplo??
tengo muchas dudas sobre como ponerlo :(....
Gracias por el curso ...
Para cuando el siguiente capitulo ?
Este finde por ahi lanzo otro video.
pd: No me spamees el blog!!
pero me gustaria como guardar los datos de una sesion en una cookie, ya que estoy haciendo un carrito de compras en zend, pero los datos los esta gurdando en una base de datos, pero la recomendacion que me dieron fue que gurdara la informacion en una cookie.
Si puedes redponderme ha esta pregunta estaria muy agradecido
http://framework.zend.com/manual/en/zend.http.cookies.html
Class Application_Model_LibraryAcl extends Zend_Acl {
public function __construct() {
$this->add(new Zend_Acl_Resource('cotizaciones'));
$this->add(new Zend_Acl_Resource('listar'), 'cotizaciones');
$this->addRole(new Zend_Acl_Role('user'));
$this->addRole(new Zend_Acl_Role('admin'),'user');
$this->allow('user', 'cotizaciones', 'listar');
$this->allow('admin', 'cotizaciones', 'index');
$this->allow('admin', 'cotizaciones', 'edit');
$this->allow('admin', 'cotizaciones', 'delete');
}
}



Me sruge una duda, por que el mismo codigo no funciona en local, pero se sube al servidor y si funciona, logicamente con las respectivas configuraciones del config.ini
Quisiera hacerte una sugerencia, pero como vos dices, es cuestion de mejorar el aplicativo.
Crear en el controller del login o usuarios como sea una funcion tal cual
y si son validos los datos del form