Laravel, parte 10: Login

Una de las partes más importantes en una aplicación web son los sistemas de login o autentificación, esto definirá las páginas de un sitio que pueda acceder un usuario, e incluso en algunos casos, como Facebook, la aplicación misma. Aunque claro, esto también dependerá los permisos con los que cuente un usuario.

En esta ocasión crearemos un pequeño sistema para loguear a un usuario, desloguearlo, y verificar si tiene acceso o no.

En primer lugar vamos a abrir nuestra consola, y vamos a entrar a nuestro proyecto:

cd C:\xampp\htdocs\mi_proyecto_laravel

Y escribimos lo siguiente:

php artisan key:generate

De esta manera generaremos un tipo de clave para nuestro sistema.

Ahora vamos a ir a app -> config -> auth.php y vamos a abrir este archivo:

Aquí encontramos un script con un array con varios valores. Uno de ellos es “driver”, el cual puede tener dos valores: “eloquent” o “database”. El primero es para realizar un login mediante el modelo User y el segundo directo en la tabla. En nuestro caso lo dejaremos en “eloquent”:

'driver' => 'eloquent',

También debemos definir el nombre del modelo. Como el nombre de nuestro modelo también es “User”, lo dejaremos así:

'model' => 'User',

También tendremos el nombre de la tabla, pero como trabajaremos desde nuestro modelo, también lo dejaremos como está. Aunque lo más probable es que esté apuntando a la tabla “users”:

'table' => 'users',

Y finalmente “reminder” tampoco lo tocamos:

'reminder' => array(
   'email' => 'emails.auth.reminder',
   'table' => 'password_reminders',
   'expire' => 60,
),

Bien, ahora para continuar debemos hacer algunos cambios en nuestro modelo User, así que vamos a ir app -> models -> User.php y vamos a editar este archivo:

<?php
use Illuminate\Auth\UserInterface;
class User extends Eloquent implements UserInterface {
   public static $rules = array(
      'real_name' => 'required|min:2',
      'email' => 'required|email|unique:users,email,id',
      'password' => 'required',
      'level' => 'required|numeric'
   );
   public static $messages = array(
      'real_name.required' => 'El nombre es obligatorio.',
      'real_name.min' => 'El nombre debe contener al menos dos caracteres.',
      'email.required' => 'El email es obligatorio.',
      'email.email' => 'El email debe contener un formato válido.',
      'email.unique' => 'El email pertenece a otro usuario.',
      'password.required' => 'La contraseña es obligatoria.',
      'level.required' => 'El nivel es obligatorio.',
      'level.numeric' => 'El nivel debe ser numérico.'
   );
   public static function validate($data, $id=null){
      $reglas = self::$rules;
      $reglas['email'] = str_replace('id', $id, self::$rules['email']);
      $messages = self::$messages;
      return Validator::make($data, $reglas, $messages);
   }
   public function getAuthIdentifier(){
      return $this->getKey();
   } 
   public function getReminderEmail(){
      return $this->email;
   } 
   public function getAuthPassword(){
      return $this->password;
   }
}
?>

Vamos a analizar los cambios. Por empezar, implementamos nuestra clase User la interfaz UserInterface, la cual nos solicitará que creemos tres métodos obligatorios: getAuthIdentifier()getReminderEmail()getAuthPassword():

public function getAuthIdentifier(){
   return $this->getKey();
} 
public function getReminderEmail(){
   return $this->email;
} 
public function getAuthPassword(){
   return $this->password;
}

El primer método es el valor que identificará al usuario logueado, osea su id. Y el email y password serán los datos, que combinados correctamente, permitirán el logueo del usuario.

Ahora vamos a pasar a la acción. Primero vamos a ir app -> controllers y vamos a crear un controlador nuevo al que llamaremos AuthController.php. Vamos a editarlo con el siguiente código:

<?php
class AuthController extends BaseController {
   public function getLogin() {
      return View::make('auth.login');
   }
   public function postLogin() {
      $user_data = array(
         'email' => Input::get('email'),
         'password' => Input::get('password')
      );
      if(Auth::attempt($user_data)){
         return Redirect::to('auth/welcome');
      }else{
         return $this->getLogin()->with('error', 'Usuario o contraseña incorrectos.');
      }
   } 
   public function getWelcome(){
      if(Auth::check()){
         $user = Auth::user();
         return View::make('auth.welcome')->with('user', $user);
      }else{
         return $this->getLogin();
      }
   }
   public function getLogout(){
      if(Auth::check()){
         Auth::logout();
      }
      return Redirect::to('auth/login');
   }
}
?>

En primer lugar tendremos una acción:

public function getLogin() {
   return View::make('auth.login');
}

Que nos devolverá una vista llamada login, el cual contendrá un formulario para ingresar el email y la contraseña.

Entonces vamos a crear nuestra vista yendo a app -> views, y dentro crearemos una carpeta llamada auth. Dentro de esta carpeta vamos a crear la vista llamada login.blade.php con el siguiente código:

<!DOCTYPE html>
<html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title> Login </title>
 </head>
 <body>
    <h1> Inicio de sesión </h1>
    @if(isset($error))
       <p> <strong> {{ $error }} </strong> </p>
    @endif 
    {{ Form::open(array('url' => 'auth/login')) }} 
       {{ Form::label('email', 'Email') }}
       <br />
       {{ Form::text('email', '') }}
       <br />
       {{ Form::label('password', 'Contraseña') }}
       <br />
       {{ Form::password('password', '') }}
       <br /> 
       {{ Form::submit('Enviar') }} 
    {{ Form::close() }}
 </body>
</html>

A estas alturas deberías entender perfectamente el código. Es un simple formulario para ingresar el email y la password.

También tendremos una acción llamada postLogin():

public function postLogin() {
   $user_data = array(
      'email' => Input::get('email'),
      'password' => Input::get('password')
   );
   if(Auth::attempt($user_data)){
      return Redirect::to('auth/welcome');
   }else{
      return $this->getLogin()->with('error', 'Usuario o contraseña incorrectos.');
   }
}

Vale aclarar que si bien ambos métodos getLogin() y postLogin() se accederán mediante el path “/auth/login”, cuando la petición venga por GET la aplicación llamará el método getLogin(), y cuando venga por POST, claro está, se llamará al método postLogin().

Osea, hablando en criollo, getLogin() nos mostrará el formulario para ingresar el email y el password, mientras que el método postLogin() será la acción que reciba los valores de los campos de ese formulario.

Y volviendo al método postLogin() analizaremos su contenido. En primer lugar recuperará los campos de formulario:

$user_data = array(
   'email' => Input::get('email'),
   'password' => Input::get('password')
);

Finalmente mediante el método attempt() de la clase Auth, recibimos el array como parámetro donde se guarda el email y la password:

if(Auth::attempt($user_data)){
   return Redirect::to('auth/welcome');
}else{
   return $this->getLogin()->with('error', 'Usuario o contraseña incorrectos.');
}

Si los datos son correctos redireccionará a la acción getWelcome(), pero de lo contrario llamará al método getLogin(), que es el que cargará la vista con el formulario nuevamente, pero pasándole el error:

return $this->getLogin()->with('error', 'Usuario o contraseña incorrectos.');

Por eso dentro de esta vista la línea login.blade.php:

@if(isset($error))
   <p> <strong> {{ $error }} </strong> </p>
@endif

Con respecto a la acción getWelcome():

public function getWelcome(){
   if(Auth::check()){
      $user = Auth::user();
      return View::make('auth.welcome')->with('user', $user);
   }else{
      return $this->getLogin();
   }
}

Como dijimos antes, aquí es donde se accederá si el email y la password son correctos, pero además una cosa que hay que tener en cuenta es que aquí se comprobará si el usuario ha iniciado una sesión correctamente, mediante el método check():

if(Auth::check()){
   $user = Auth::user();
   return View::make('auth.welcome')->with('user', $user);
}else{
   return $this->getLogin();
}

Si el usuario no está logueado lo redireccionará al formulario de login. Pero de estarlo recuperará el objeto User con los datos de éste, gracias al método user(), y se lo pasará a la vista welcome.

$user = Auth::user();
return View::make('auth.welcome')->with('user', $user);

Para ello vamos a ir a app -> views -> auth, y vamos a crear una nueva vista llamada: welcome.blade.php, la cual editaremos con el siguiente código:

<!DOCTYPE html>
<html>
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title> Bievenido </title>
 </head>
 <body>
    <h1> Bienvenido {{ $user->real_name }} </h1>
    <p> Usted está ahora logueado </p>
    <p> {{ link_to('/auth/logout', 'Cerrar sesión') }} </p>
 </body>
</html>

Aquí simplemente mostraremos un mensaje de bienvenida, y saludamos al usuario por su nombre. Además tendremos un enlace que irá a la acción getLogout(), para desloguear al usuario:

public function getLogout(){
   if(Auth::check()){
      Auth::logout();
   }
   return Redirect::to('auth/login');
}

Para cerrar sesión llamamos al método logout() y lo redireccionamos al formulario de login.

Además, también, podríamos hacer una validación de login un poco más trabajada. Cuando creamos la tabla usuarios, habíamos agregado una columna active. Por tanto, podemos asignar una nueva condición, que no sólo exista un usuario con ese email y contraseña, sino que también esté activo. Entonces, para ello vamos a cambiar el siguiente código del método postLogin():

$user_data = array(
   'email' => Input::get('email'),
   'password' => Input::get('password')
);

Por éste:

$user_data = array(
   'email' => Input::get('email'),
   'password' => Input::get('password'),
   'active' => true
);

Ahora sólo nos resta agregar este controlador a nuestro archivos routes.php, así que vamos a app -> routes.php y agregamos la siguiente línea:

Route::controller('auth', 'AuthController');

Ya podemos probar nuestro proyecto iniciando el servidor y yendo a:

https://localhost:8000/auth/login

Bueno, ahora para finalizar la publicación, podemos cambiar nuestro controlador UsersController, que habíamos hecho en el anterior posteo con el siguiente código:

<?php
class UsersController extends BaseController { 
   private $autorizado;
   public function __construct() {
      $this->autorizado = (Auth::check() and Auth::user()->level == 5);
   } 
   public function index() {
      if(!$this->autorizado) return Redirect::to('/auth/login');
      $users = User::all();
      return View::make('users.index')->with('users', $users);
   }
   public function show($id) {
      if(!$this->autorizado) return Redirect::to('/auth/login');
      $user = User::find($id);
      return View::make('users.show')->with('user', $user);
   }
   public function create() {
     if(!$this->autorizado) return Redirect::to('/auth/login');
     $user = new User();
     return View::make('users.save')->with('user', $user);
   }
   public function store() {
      if(!$this->autorizado) return Redirect::to('/auth/login');
      $user = new User();
      $user->real_name = Input::get('real_name');
      $user->email = Input::get('email');
      $user->password = Hash::make(Input::get('password'));
      $user->level = Input::get('level');
      $user->active = true;
      $validator = User::validate(array(
         'real_name' => Input::get('real_name'),
         'email' => Input::get('email'),
         'password' => Input::get('password'),
         'level' => Input::get('level'),
      ));
      if($validator->fails()){
         $errors = $validator->messages()->all();
         $user->password = null;
         return View::make('users.save')->with('user', $user)->with('errors', $errors);
      }else{
         $user->save();
         return Redirect::to('users')->with('notice', 'El usuario ha sido creado correctamente.');
      }
   }
   public function edit($id) {
      if(!$this->autorizado) return Redirect::to('/auth/login');
      $user = User::find($id);
      return View::make('users.save')->with('user', $user);
   }
   public function update($id) {
      if(!$this->autorizado) return Redirect::to('/auth/login');
      $user = User::find($id);
      $user->real_name = Input::get('real_name');
      $user->email = Input::get('email');
      $user->level = Input::get('level');
      $validator = User::validate(array(
         'real_name' => Input::get('real_name'),
         'email' => Input::get('email'),
         'password' => $user->password,
         'level' => Input::get('level'), 
 ), $user->id);
      if($validator->fails()){
         $errors = $validator->messages()->all();
         $user->password = null;
         return View::make('users.save')->with('user', $user)->with('errors', $errors);
      }else{
         $user->save();
         return Redirect::to('users')->with('notice', 'El usuario ha sido modificado correctamente.');
      }
   }
   public function destroy($id) {
      if(!$this->autorizado) return Redirect::to('/auth/login');
      $user = User::find($id);
      $user->delete();
      return Redirect::to('users')->with('notice', 'El usuario ha sido eliminado correctamente.');
   }
}
?>

Como se ve en el código, tenemos una propiedad $autorizado:

private $autorizado;

La cual guardará si el usuario tiene acceso o no al módulo UsersController.

Dentro del constructor guardamos el valor de esa propiedad $autorizado:

public function __construct() {
   $this->autorizado = (Auth::check() and Auth::user()->level == 5);
}

Presumo que ya debés saberlo, pero si no es así, un constructor es un método que será ejecutado una vez que se cree el objeto, por tanto el método constructor será llamado antes que cualquier de los otros, y comprobará si el usuario está autorizado para entrar en ese módulo.

La validación será que está logueado, y que además que tenga un nivel (level) igual a 5, osea el nivel más importante para un usuario. Luego en cada acción preguntamos si el usuario no está autorizado y de ser así, lo redireccionamos al login:

if(!$this->autorizado) return Redirect::to('/auth/login');

Bien, con esto terminamos esta publicación.

Saludos!

Descargar ejemplo

Anterior: Laravel, parte 9: Validaciones

Siguiente: Laravel, parte 11: Modelos y relaciones

Redes sociables

    19 Replies to “Laravel, parte 10: Login”

    1. buenas noches he seguido el tutorial paso a paso pero no me funciona sera que me puede ayudar realmente lo nesecito

    2. Excelente tutorial, son nuevo en laravel pero me surge una duda con respecto a autenticar usuarios en laravel , segun le leido es obligatorio tener una tabla llamada users y que contenga como minimo email y password , que pasa si mi tabla donde tengos los usarios es una vista compuesta por varias tablas y no tengo ni el campo email ni el password se puede usar la autenticacion de laravel o que debo configurar para que me funcione.

      saludos y esperando tu respuesta

      1. En realidad sí, deberías hacer una consulta con Eloquent verificando las reglas que deben cumplirse para que esté correcto el usuario, y de serlo, crear una sesión manualmente.

        La creás con:
        Session::put(‘identificador’, ‘Valor’);

        Y la recuperás con:

        Session::get(‘identificador’);

        Acá te dejo el enlace con la documentación de Laravel:

        http://laravel.com/docs/session

        Saludos!

    3. una pregunta cunado le doy cerrar sesion no me manda al login se queda en la pagina de logout, hasta que actualizo el navegador me manda de nuevo a login, que puedo hacer, lo de inciar lo reslvi de esta forma en el archivo User.php agregue esto, que por default te lo crea laravel…
      use Illuminate\Auth\UserTrait;
      use Illuminate\Auth\UserInterface;
      use Illuminate\Auth\Reminders\RemindableTrait;
      use Illuminate\Auth\Reminders\RemindableInterface;

      class User extends Eloquent implements UserInterface, RemindableInterface {

      y al final las funciones que te da la pagina oficial

      public function getRememberToken()
      {
      return $this->remember_token;
      }

      public function setRememberToken($value)
      {
      $this->remember_token = $value;
      }

      public function getRememberTokenName()
      {
      return ‘remember_token’;
      }

      dejando las que ya tenia de tu codigo, y funciona perfecto el unico problema es en el logout, que cuando le doy cerrar sesion se queda ne la pagina de auth/logout y no hace la redireccion a login, otra cosa si quieren ir a administrar los usuarios solo es agregar un link en la pagina de bienvenido asi {{ link_to(‘/users’, ‘administrar’) }} … espero me ayuden con lo de logout gracias

    4. Disculpen las molestias ya lo resolvi gracias por el tutorial esta super chingon muchas gracias ya converti los 8 capitulos a un pdf por si gustas te lo mando para que lo subas a tu servidor… bueno esta es la forma en como lo resolvi, a lo mejor la forma de enviar el mensaje de gracias por la visita no es muy funcional o practico pero sirve perfecto dejo el codigo….

      public function getLogout(){

      if(Auth::check()){

      Session::flush();
      }
      return $this->getLogin()->with(‘error’, ‘Gracias por visitarnos’);

      }

    5. Buen día… he seguido el tutorial y me ha ayudado mucho, gracias. Quiero implementar un login usando Facebook. Hay alguna forma simple para hacerlo con Laravel?

      1. Sinceramente no sé. Pero de cualquier manera no creo que dependa de Laravel, sino del plugin de Facebook. Yo creo que deberías investigar más por ese lado.

        Saludos!

    6. Muchas gracias por todo , tengo una inquietud estoy realizando un foro en laravel y quiero cambiar

      a blade de laravel pero no me da el resultado que deseo con
      {{ Form::text(‘title’,”,array(‘class’=>’control-label’,’id’=>’inputSuccess3′,’aria-describedby’=>’inputSuccess3Status’)) }}
      no me esta reconociendo la clase control-label
      muchas gracias por su respuesta

        1. input type=”text” class=”form-control” id=”inputSuccess3″ aria-describedby=”inputSuccess3Status

        1. si , la extención esta en .blade.php , pero deseo que esto
          input type=”text” class=”form-control” id=”inputSuccess3″ aria-describedby=”inputSuccess3Status
          se convierta en blade para un formulario pero no me genera lo que deseo con
          {{ Form::text(‘title’,”,array(‘class’=>’control-label’,’id’=>’inputSuccess3′,’aria-describedby’=>’inputSuccess3Status’)) }}

          1. Así:

            {{ Form::text(‘inputSuccess3’, ”, array(‘class’ => ‘form-control’, ‘aria-describedby’ => ‘inputSuccess3Status’)) }}

    Comments are closed.