YII – Autenticación de usuarios + ultimo acceso

Este post tiene por objetivo crear la funcionalidad de autenticación de usuarios contra una base de datos usando el humilde y eficiente framework YII.

Se pretende con este post ampliar la explicación del capitulo 9 de la GUIA BASICA DE YII FRAMEWORK añadiendo algunos detalles como la captura y gestión del la fecha del ultimo acceso al sistema por cada usuario, condicionar mostrar elementos del menú según el perfil del usuario.

Creamos la tabla que vamos a usar para la practica en este caso estamos usando como base de datos postgreSQL, creamos la columna created_at que guardara automáticamente la fecha en que se ingresa cada registro haciendo uso de la función de postgres now().

CREATE TABLE usuario
 (
 id_usuario serial NOT NULL,
 cedula character varying(12) NOT NULL,
 nombre character varying(50) NOT NULL,
 apellido character varying(50) NOT NULL,
 email character varying(100) NOT NULL,
 username character varying(128) NOT NULL,
 password character varying(128) NOT NULL,
 perfil character varying(10) NOT NULL,
 created_at timestamp without time zone DEFAULT now(),
 last_login timestamp without time zone,
 CONSTRAINT usuario_pkey PRIMARY KEY (id_usuario )
 );
created_at-last-login-php-yii

created_at-last-login-php-yii

Se deberá autogenerar el modelo y el CRUD para esta tabla usando el modulo gii (YII code generator). Acceden a el con este url http://localhost/sistema/index.php?r=gii

En lo sucesivo es importante que antes de modificar cualquier archivo realicen una copia del mismo por si se trancan o no resulta puedan restituir y revisar con calma desde el comienzo.

Sustituiremos el contenido del archivo protected/components/UserIdentity.php por lo siguiente:

<?php /** * UserIdentity represents the data needed to identity a user. * It contains the authentication method that checks if the provided * data can identity the user. */
class UserIdentity extends CUserIdentity {
private $_id;
public function authenticate(){
$username=strtolower($this->username);
$user=Usuario::model()->find('LOWER(username)=?',array($username));
if($user===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else if(!$user->validatePassword($this->password))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else{
$this->_id=$user->id_usuario;
$this->username=$user->username;
$this->errorCode=self::ERROR_NONE;

/*Consultamos los datos del usuario por el username ($user->username) */
$info_usuario = Usuario::model()->find('LOWER(username)=?', array($user->username));
/*En las vistas tendremos disponibles last_login y perfil pueden setear las que requieran */
$this->setState('last_login',$info_usuario->last_login);
$this->setState('perfil',$info_usuario->perfil);

/*Actualizamos el last_login del usuario que se esta autenticando ($user->username) */
$sql = "update usuario set last_login = now() where username='$user->username'";
$connection = Yii::app() -> db;
$command = $connection -> createCommand($sql);
$command -> execute();

}
return $this->errorCode==self::ERROR_NONE;
}

public function getId(){
return $this->_id;
}

}

Las lineas 22, 23, 24 y 25 son las que hacen la magia de guardar la fecha, hora, minutos y segundos actual en el campo dispuesto para almacenar el ultimo acceso del usuario cuyas credenciales (usuario y contraseña) para entrar al sistema sean validas.

luego debemos agregar en el Modelo relacionado a la tabla usuario lo necesario para que convierta la contraseña que se envía desde el formulario de login al metodo de su preferencia, en esta practica usaremos MD5 para luego comparar la cadena resultante con la cadena ya almacenada en el campo password en la tabla usuario.

En el archivo protected/models/Usuario.php

agregaremos las siguientes lineas:


public function validatePassword($password){
return $this->hashPassword($password)===$this->password;
}

public function hashPassword($password){
return md5($password);
}

Por si tienen dudas, las lineas anteriores van dentro de la clase Usuario (después de: class Usuario extends CActiveRecord { y antes del ultimo } )

Ahora es el turno de agregar y ajustar un par de lineas en el controlador ( protected/controllers/UsuarioController.php ) para que todo marche bien.

Es necesario que cuando se cree o se modifique un usuario la cadena de caracteres que representa la contraseña sea guardado en MD5 para asi ser guardado en la Base de Datos.

Para esto solo agregaremos una linea que pasa la cadena a MD5  $model->password=md5($model->password); antes de guardar o modificar


public function actionCreate()
{
$model=new Usuario;

// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);

if(isset($_POST['Usuario']))
{
$model->attributes=$_POST['Usuario'];
$model->password=md5($model->password); //agregar esta linea antes del save() lo mismo en la funcion de modificar actionUpdate()

if($model->save())
$this->redirect(array('view','id'=>$model->id_usuario));
}

$this->render('create',array(
'model'=>$model,
));
}

Para que puedan tener acceso a los módulos de editar, crear, eliminar, el admin y demás es necesario agregar permisos en accessRules(), indicando que podrán ser usados esos módulos por todos los usuarios que estén autenticados con el símbolo @ o directamente el nombre del usuario.

En el siguiente código indicaremos que crear y modificar usuarios solo lo podrá hacer el usuario leninmhs y accederán al modulo admin de usuarios todos los usuarios autenticados.

public function accessRules()
{
return array(
array('allow',  // allow all users to perform 'index' and 'view' actions
'actions'=>array('index','view'),
'users'=>array('*'),
),
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create','update','delete'),
'users'=>array('leninmhs'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin'),
'users'=>array('@'),
),
array('deny',  // deny all users
'users'=>array('*'),
),
);
}

En caso contrario se toparan con este mensaje de error que les indica que no están autorizados para usar estos módulos.

Error 403

You are not authorized to perform this action.
De este punto en adelante solo trabajaremos en las vistas ( todos los directorios y archivos que se encuentran en: protected/views/ )

Si auto generaron el crud en base a la tabla que se presento al inicio, en el archivo protected/views/usuario/_form.php deberán quitar o comentar como mejor le parezca las lineas de código que forman los campos de created_at y last_login ya que esto se llena tras bambalinas.


<div>
<?php //echo $form->labelEx($model,'created_at'); ?>
<?php //echo $form->textField($model,'created_at'); ?>
<?php //echo $form->error($model,'created_at'); ?>
</div>

<div>
<?php //echo $form--->labelEx($model,'last_login'); ?>
<?php //echo $form->textField($model,'last_login'); ?>
<?php //echo $form->error($model,'last_login'); ?>
</div>

en caso contrario obtendrán un error como este:

CDbCommand failed to execute the SQL statement: SQLSTATE[22007]: Invalid datetime format: 7 ERROR: la sintaxis de entrada no es válida para tipo timestamp: «»
LINE 1: …inmhs’, ’74be16979710d4c4e7c6647856088456′, ‘ADMIN’, ”, ”)
^. The SQL statement executed was: INSERT INTO “usuario” (“cedula”, “nombre”, “apellido”, “email”, “username”, “password”, “perfil”, “created_at”, “last_login”) VALUES (:yp0, :yp1, :yp2, :yp3, :yp4, :yp5, :yp6, :yp7, :yp8)

Ahora vamos a imprimir la fecha del ultimo acceso cuando el usuario este autorizado a para usar el sistema y vamos a mostrar el menú de acceso al modulo de usuarios solo si el perfil del usuario es de administrador ( ADMIN )

modificaremos el archivo: protected/views/layouts/main.php

<div id="mainmenu">
<?php

$admin = (isset(Yii::app()->user->perfil) and Yii::app()->user->perfil == 'ADMIN') ? true : false ;
$this->widget('zii.widgets.CMenu',array(
'items'=>array(
array('label'=>'Home', 'url'=>array('/site/index')),
array('label'=>'About', 'url'=>array('/site/page', 'view'=>'about')),
array('label'=>'Contact', 'url'=>array('/site/contact')),
array('label'=>'Usuarios', 'url'=>array('/usuario/admin'), 'visible' => $admin),
array('label'=>'Login', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),
array('label'=>'Salir ('.Yii::app()->user->name.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest)
),
)); ?>
</div><!-- mainmenu -->

<div style="text-align: right;">
<?php if(!Yii::app()->user->isGuest and isset(Yii::app()->user->last_login)){
echo "Ultimo Acceso: ".Yii::app()->dateFormatter->format("d-M-y h:m a", Yii::app()->user->last_login);} ?>
</div>

Básicamente nos interesa:

  • La linea 4 y la 10 que muestra o oculta la opción de menu que lleva a la administración de usuarios mediante la opción “visible” de CMenu.que solo acepta valores booleanos, es por esto que antes creamos una variable de nombre $admin el cual mediante un if ternario le asigno true o false según sea o no ADMIN.
  • De la linea 17 a la 20 validamos si el usuario se autentico y si tiene fecha de ultimo acceso para proceder a darle formato a la fecha en cuestión y imprimirla.

De modo que se tienen dos usuarios uno con perfil ADMIN y otro con un perfil distinto, el primero vera la opción de ir a la administración de usuarios y el segundo no.

last-login-yii-cmenu

last-login-yii-cmenu

El resultado final debería ser algo como esto:

Anuncios

34 comentarios en “YII – Autenticación de usuarios + ultimo acceso

  1. Gracias por el tutorial, muy bien explicado. Una duda, en la linea:
    $admin = (isset(Yii::app()->user->perfil) and Yii::app()->user->perfil == ‘ADMIN’) ? true : false ;

    la palabra perfil es un campo de la base de datos?

    Gracias!

  2. La primera linea del UserIdentity,php me generaba un error.

    $username=strtolower($this—>username);

    Cambienla por esta-

    $username=strtolower($this->username);

    Gracias por el tuto!

    • Cuando dices que no te lo reconoce YII es que no logras la autenticación con esos usuarios? o que no lo ves en el admin de yii? intenta comparar y verificar los pasos que realizaste con los de esta entrada…

  3. La funcion accessRules muestra de forma muy clara como setear los permisos de acceso por usuario, hay forma de hacerlo por PERFIL ?
    Gracias

  4. […] Autenticación y Autorización: Yii tiene incorporado mecanismos de autenticación y autorización muy completos que permiten la adecuación para necesidades especiales. También es compatible con autorización a través del control de acceso basado en roles.Yii autentica por defecto de manera rápida y sencilla contra usuarios en un archivo php (sistemayii/protected/components/UserIdentity.php) donde se pueden agregar los necesarios, también claro esta contra una base de datos, un LDAP, etc..  Ver entrada sobre autenticación […]

  5. Hola que tal lennin como estas, lennin hago todos los pasos con mucho cuidado pero pasa algo cuando voy a ingresar con los usuarios que tengo creado en la BD no me deja acceder y me msj de error q el usuario o el password pueden ser incorrectos. Y esta tal cual, claro la unica diferencia es q la clave no esta en MD5 ya que agregue los usuarios a pedal y pulmón x postgres..! Que podrá ser estoy viendo si puedo hacer el logueo de Tutorial de PostgreSQL..

  6. Hola amigo espero te encuentres bn. Lenin tengo una duda xq en el ejemplo que presentas creas una tabla usuario con el schema public por defecto. Ahora viene la gran duda ya que tengo mi tabla usuario dentro de un schema distinto al public y por tal motivo el ejemplo que presentas no me funciona. Que tendria que modificar ? Me supongo que las modificaciones serian mas que todo en el controlador y el modelo. Gracias x ese gran aporte!!

    • No tienes que modificar nada en realidad!! cuando vallas a usar el Model Generator desde Gii, coloca el nombre del esquema.tutabla, si tu esquema se llama por ejemplo “compartido”, entonces colocaras compartido.usuario y listo en la funcion tableName del modelo Usuario.php que genere colocara “compartido.usuario2”
      Adicionalmente si haces alguna consulta usando sql directo como el update usuario deberias colocar update tuesquema.usuario
      Saludos!!

  7. […] * Para profundizar ó indagar mas revisen la propia clase en www/yii/framework/web/CDbHttpSession.php y su documentación: http://www.yiiframework.com/doc/api/1.1/CDbHttpSession * Estoy almacenando el id del usuario que inicia session con Yii::app()->user->id en una entrada anterior pueden indagar sobre la autenticación de usuarios: https://leninmhs.wordpress.com/2012/08/26/yii-autenticacion-last-login/ […]

  8. al momento de actualizar un registro y no se cambiar la contraseña al momento de guardar los cambios cambia el paswword por el registrado en el md5, como solucionar esto

  9. Soy un usuario con pocos conocimientos de PHP y de Yii y buscando información di con tú guía básica y quería agradecerte el tiempo que te tomaste en elaborar tan buen material de estudio y el hecho de dejarlo disponible para quien quiera descargarlo. Si no lo tomas a mal me gustaría recomendar también a quien busque más información la serie de vídeos de Gustavo Salgado en youtube(http://www.youtube.com/user/Gustalh). Saludos

  10. Saludos,
    Alguien me puede ayudar?
    La tuto me servido mucho, Gracias!
    pero tengo un pequeño problema en la parte final en el menú no se ocultan los etiquetas que supuestamente no se tiene acceso, es decir me muestra TODO sin ocultar las que no debería mostrar. El nivel de acceso lo cumple perfectamente, pero no oculta en el menu.
    Si pueden ayudarme se los agradecería bastante!!!

    • En esta practica solo estamos usando condicionales (IF) asi lo refleje:
      $admin = (isset(Yii::app()->user->perfil) and Yii::app()->user->perfil == ‘ADMIN’) ? true : false ;
      luego: poner visible true o false asi lo deje: array(‘label’=>’Usuarios’, ‘url’=>array(‘/usuario/admin’), ‘visible’ => $admin),
      Pudieras poner un par de if o case segun necesites… Saludos!!

  11. Hola que tal, mira este ejemplo me sirvió de mucho para mi proyecto universitario pero mira, ya aplique todo y no me genera ningun error, no uso la misma tabla que tu pero me funciona pero a la hora de poner $admin = (isset(Yii::app()->user->rol_GU) and Yii::app()->user->rol_GU == ‘Administrador’) ? true : false ; y luego asignar a cada espacio del menu que quiero que entre, por ejemplo array(‘label’=>’Usuarios’,’url’=>array(‘/user/admin’),’visible’ => $admin),

    Resulta que cuando entro con un usuario que tiene el rol de administrador no me aparece ese espacio, me lo oculta como si el usuario no tiene como rol o perfil administrador.

    como podrás ver a todo lo que tu tienes como perfil yo lo tengo como rol_GU, pero eso es lo de menos, no se si es que no se esta conectando bien o no se.

    la tabla que yo tengo es: id_GU – username – password – rol_GU – identificación_GU y pues solo no le inclui todo aquello que decia last_login y pues bueno, si no me da error de nada todo esta bien solo que no se por qué cuando lo especifico no aparece, o sea si no estoy autentificado no me aprese y cuando me autentifico tampoco aparece. Porfa ocupo ayuda en esto.

    • bueno ya encontré el problema, soluciono mi problema solamente fue que no agregué la siguiente linea $this->setState(‘perfil’,$info_usuario->perfil); ..bueno gracias, me sirvió de mucho este ejemplo, saludos

  12. Pues muchísimas gracias por el tutorial. De momento quiero tocar el tema de las vistas, que me falta eso, pero hasta ahora me ha sido de mucha ayuda. Solo un pequeño apunte. Para que me pudiese leer bien las contraseñas encriptadas, además de todo lo que dices, en protected/components/UserIdentity.php me ha tocado, en el método authenticate() cambiar la línea

    else if(($users->clave != $this->password) && $users!==null)

    por

    else if(($users->CampoCalveTabla != md5($this->password)) && $users!==null)

    para que también, al comprobar que no coinciden, transforme la contraseña, ya que si no me daba error todo el rato.

    Un saludo y gracias de nuevo

    • perdón. $users->clave es igual que $users->CampoCalveTabla. Ahí habría que poner el nombre del la columna donde almacenéis la contraseña en vuestra tabla de usuarios de la BBDD

  13. Compadre me salvaste la tarde estuve mas de 4 horas tratando de hacer esto y no podia, vi tu tutorial y me demore menos de 5 minutos en areglar el error saludos men

  14. Hola, muy bueno el tutorial, me funciona todo perfectamente, solo que cuando edito el usuario para cambiar otro campo y guardo, luego no puedo ingresar con ese usuario, me dice que el usuario o contraseña son incorrectos, alguien que me de euna mano en solucionar esto, es lo unico que me falta por resolver.
    Saludos y gracias de antemano!!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s