IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Canvis a Laravel 5.3

See changes in Laravel 5.3: https://josephsilber.com/posts/2016/07/10/authentication-improvements-in-laravel-5-3

Configuració i requeriments

Per tal de poder activar un sistema d'autenticació és requereix configurar prèviament els proveïdors d'usuaris i els Guards (vegeu fitxer config/auth.php):

  • Guard: Defineixen com els usuaris són auneticats per a cada petició HTTP (HTTP request). Laravel porta per defecte dos guards:
web/session guard: el guard més habitual en pàgines web on l'autenticació es basa en autenticació per formulari de login/password i és manté l'estat utilitzant cookies i sessions
Token: un sistema bàsic basat en tokens simple. Cada request ha de proporcionar un token per autenticar l'usuari. Cal configurar base de dades per afegir camp token. Vegeu també Laravel Passport com un sistema més elaborat amb suport per Oauth
  • Laravel Passport proporciona un altre guard basat en OAuth
  • Qualsevol objecte que implementi la interfície Guard ([1]) pot ser un guard vàlid i per tant podem customitzar Laravel creant els nostres propis Guards. Llegiu [2]
  • User Provider: com diu el seu nom és tracta d'un servei que ens proporcionarà la informació sobre els usuaris de l'aplicació. Aquest servei s'ha de connectar a la base de dades on estan els usuaris i proporcionar-los. Cal fixar-se que utilitzem la paraula base de dades en forma molt general no només ens referim a base de dades relacional, és a dir, que realment estem fent referència a qualsevol sistema de persistència on estiguin emmagatzemat els usuaris. Exemple: fitxer, servidor Ldap, base de dades en memòria com Redis/Memcached

La configuració es realitza al fitxer config/auth.php:

https://github.com/laravel/laravel/blob/master/config/auth.php

La configuració per defecte és:

  • Guard per defecte: web/session que utilitza per obtenir els usuaris el user provider users
  • User provider per defecte: users que obté les dades dels usuaris utilitzant Eloquent i el model App\User

Recursos:

Introducció

Laravel ofereix per defecte un sistema d'autenticació complet amb les següents funcionalitats:

  • Base de dades amb migracions (taules users i password_resets)
  • Model de base de dades (User class)
  • Vistes i funcionalitats
  • Registre de nous usuaris
  • Login
  • Recuperació de paraula de pas mitjançant correu electrònic
  • Totes les vistes tenen formularis amb validació de formularis en client-side i en server-side.

Si voleu saber com s'han implementat aquestes funcionalitats llegiu l'article:

PHP Notification app. Laravel from scratch

Aquestes funcionalitats formen part del que es coneix com estructura bàsica de Laravel o Scaffolding. Aquesta estructura bàsica conté migracions, model, lògica de negoci i vistes per implementar algunes de les funcionalitats més habituals a una aplicació. Entre d'altres s'ofereix la funcionalitat d'authenticació, Bootstrap less, etc. Podeu optar per no utilitzar aquestes funcionalitats amb la comanda php artisan fresh

Si esteu buscant com controlar permisos i rols d'usuaris consulteu Laravel Authorization

Afegir camp username

Vegeu un pas a pas a:

http://www.codetutorial.io/laravel-5-rest-api-basic-authentication/

Authentication Events (auth.login and auth.attempt)

Hi ha tres esdeviments que Laravel dispara durant l'autenticació:

  • auth.attempt: Cada cop hi ha un intent d'autenticació.
  • auth.login: un usuari es logat correctament
  • auth.logout': un usuari surt del sistema

Per crear un gestor de l'esdeveniment auth.login:

$ php artisan handler:event AuthLoginEventHandler
Handler created successfully.

Això us crea el fitxer App\Handlers\Events\AuthLoginEventHandler i s'ha de modificar de la següent forma:

<?php namespace App\Handlers\Events;

use App\User;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;

class AuthLoginEventHandler {

	/**
	 * Create the event handler.
	 *
	 * @return void
	 */
	public function __construct()
	{
		//
	}

    /**
     * Handle the event.
     *
     * @param  User $user
     * @param  $remember
     * @return void
     */
	public function handle(User $user, $remember)
	{
		dd($user);
	}

}

De moment és un exemple per comprovar l'esdeveniment que el que farà és aturar la aplicació un cop el login és correcte i mostrar les dades del usuari logat.

El mètode handle respon a la línia (458 --acacha (discussió) 12:55, 29 abr 2015 (CEST)) del fitxer vendor/laravel/framework/src/Illuminate/Auth/Guard.php:

$this->events->fire('auth.login', [$user, $remember]);

Ara cal realacionar al fitxer:

app\Providers\EventServiceProvider

el handler amb l'esdeveniment:

 ...
 protected $listen = [
		'event.name' => [
			'EventListener',
		],
        'auth.login' => [
            'App\Handlers\Events\AuthLoginEventHandler',
        ],
	];
...

I recompilar:

$ php artisan clear-compiled

Ara comproveu que després de fer un login us apareix quelcom similar a:

User {#190 ▼
  #table: "users"
  #fillable: array:3 [▶]
  #hidden: array:2 [▶]
  #connection: null
  #primaryKey: "id"
  #perPage: 15
  +incrementing: true
  +timestamps: true
  #attributes: array:7 [▶]
  #original: array:7 [▶]
  #relations: []
  #visible: []
  #appends: []
  #guarded: array:1 [▶]
  #dates: []
  #casts: []
  #touches: []
  #observables: []
  #with: []
  #morphClass: null
  +exists: true
}

Un exemple més habitual es voler afegir variables de sessió després del login i/o monitoritzar l'últim cop que l'usuari es va logar:

Tingueu en compte que cal afegir una migració per al camp last_login

$ php artisan make:migration add_last_login_field_to_users_table

I editeu el fitxer database/migrations/***_add_last_login_field_to_users_table:


<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddLastLoginFieldToUsersTable extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
        Schema::table('users', function(Blueprint $table)
        {
            $table->timestamp('last_login');
        });
	}

	/**
	 * Reverse the migrations.
	 *
	 * @return void
	 */
	public function down()
	{
		//
        Schema::table('users', function(Blueprint $table)
        {
            $table->dropColumn(
                'last_login'
            );
        });

    }

}


Consulteu que teniu una migració pendent:

$ homestead ssh
$  cd ~/Code/laravel_base_app
$ php artisan migrate:status
+------+-------------------------------------------------------+
| Ran? | Migration                                             |
+------+-------------------------------------------------------+
| Y    | 2014_10_12_000000_create_users_table                  |
| Y    | 2014_10_12_100000_create_password_resets_table        |
| N    | 2015_04_29_110559_add_last_login_field_to_users_table |
+------+-------------------------------------------------------+

i executeu la migració:

$ php artisan migrate

Resources:

Informació de sessió i authenticació

Amb:

 $data = Session::all();
 dd($data);

Dins de qualsevol controlador un cop autenticat l'usuari us donarà un resultat similar a:


array:5 [▼
  "_token" => "SVwym5n72rzxb11FR8JPIP175rD6y1Jd2YXacnc"
  "_previous" => array:1 [▼
    "url" => "http://laravel.app/home"
  ]
  "flash" => array:2 [▼
    "old" => []
    "new" => []
  ]
  "url" => array:1 [▼
    "intended" => "http://laravel.app/home"
  ]
  "login_82e5d2c56bdd0811318f0cf078b78bfc" => 1
]

La variable de sessió:

login_82e5d2c56bdd0811318f0cf078b78bfc

Conté el id de l'usuari logat (a l'exemple l'usuari amb id igual a 1)

El codi del framewok Laravel el podeu trobar a:

Illuminate\Auth\Guard

De fet si feu un hash md5 del text Illuminate\Auth\Guard el resultat és:

82e5d2c56bdd0811318f0cf078b78bfc

Per tant per comprovar si hi ha un usuari logat només cal buscar si existeix la variable de sessió

login_82e5d2c56bdd0811318f0cf078b78bfc

Extending Laravel authentication

Es poden definir diferents providers per a diferents realms.

Resources

Autenticació per Middlewares

Qualsevol pàgina web podrà classificar les (sub)pàgines web per les que està formades en dos tipus:

  • Públiques: URLs a les que es pot accedir sense estar autenticat
  • Privades/Intranet: URLs a les que NO es pot accedir sense estar autenticat. Les URLs privades es poden classificar en diferent nivells d'accés utilitzant Autorització: és important no confondre l'autenticació amb l'autorització

Cal tenir en compte que Laravel com la majoria de Frameworks implementa el patró de disseny Front controller, és a dir, totes les URLs de la nostra aplicació es fan passar per un fitxer principal (index.php) que fa de controlador principal. El controlador principal utilitza un sistema bast en rutes per mapejar les diferents URLs de la nostra aplicació cap al codi/controladors dedicats per a cada URL.

El sistema ideal per complir amb SRP i no barrejar el codi d'autenticació amb altres codis és utilitzar un Middleware. Al fitxer app/Http/Kernel.php trobem el Kernel web (recordeu que també existeix el Kernel Console utilitzat per a utilitzar Laravel des de la línia de comandes amb php artisan). Al kernel web trobem predefinits els middlewares per a rutes:

https://github.com/laravel/laravel/blob/master/app/Http/Kernel.php
protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        ...
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        ....
    ];

Bàsicament com podeu veure podem protegir rutes utilitzar el middleware auth que només permetrà l'accés a la ruta si s'està autenticat. També tenim el middleware guest que només permet accedir a una ruta si NO s'està autenticat!

https://github.com/illuminate/auth/blob/master/Middleware/Authenticate.php
https://github.com/laravel/laravel/blob/master/app/Http/Middleware/RedirectIfAuthenticated.php

Si observeu els dos codis la responsabilitat de comprovar si un usuari està logat o no es delega en els Guards

Guard

A Laravel són els encarregats de comprovar l'autenticació o no d'un usuari. Vegem la interfície que ha de complir qualsevol Guard de Laravel:

https://laravel.com/api/5.3/Illuminate/Contracts/Auth/Guard.html
https://github.com/illuminate/contracts/blob/master/Auth/Guard.php
interface Guard
{
    /**
     * Determine if the current user is authenticated.
     *
     * @return bool
     */
    public function check();

    /**
     * Determine if the current user is a guest.
     *
     * @return bool
     */
    public function guest();

    /**
     * Get the currently authenticated user.
     *
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
     */
    public function user();

    /**
     * Get the ID for the currently authenticated user.
     *
     * @return int|null
     */
    public function id();

    /**
     * Validate a user's credentials.
     *
     * @param  array  $credentials
     * @return bool
     */
    public function validate(array $credentials = []);

    /**
     * Set the current user.
     *
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
     * @return void
     */
    public function setUser(Authenticatable $user);
}

Els mètodes són:

  • check: comprova si l'usuari està autenticat retornat true o false. Observeu que no té mètodes d'entrada és a dir que cada guard buscarà en un estat predefinit si l'usuari està logat o no (el guard de sessió mirà la sessió, els de Token si hi ha un token, etc.)
  • guest: el contrari de check normalment. Mirà si l'usuari NO està logat
  • user(): retorna l'usuari logat. Retorna un objecte que implementi l'interfície Auntheticable
  • id(): retorna l'identificador de l'usuari logat
  • validate(): se li passen les credencials i es comprova si són vàlides.
  • setUser(): estableix l'usuari logat

On s'utilitzen?

  • Check() i guest() a els middlewares encarregats de comprovar l'autenticació
  • User() i id(). Per obtenir les dades de l'usuari en pàgines privades
  • validate() i setUser(): al procés de Login (formulari de Login de l'usuari)



Web/Session Guard

És el guard utilitzat per defecte segons el fitxer config/auth.php. Correcte però quan es carrega aquest Guard a Laravel? Doncs on es carreguen tots els objectes durant l'arrancada d'una app Laravel utilitzant els Service Providers del fitxer config/app.php. Observareu dos que poden semblar relacionats amb l'Autenticació:

Illuminate\Auth\AuthServiceProvider::class
App\Providers\AuthServiceProvider::clas --> NO

IMPORTANT: AuthServiceProvider fa referència a Authorization i no pas a Aunthentication

Per tant el que ens interessa és:

 Illuminate\Auth\AuthServiceProvider [3]

Com podeu veure s'utilitza AuthManager/Illuminate\Auth\AuthManager per gestionar els Guards i els User Providers. Aquesta classe retorna el Guard que pertoqui segons la configuració del fitxer config/auth.php

AuthManager és registra al contenidor com auth
AuthManager->guard() retorna el guard que estarà disponible al contenidor com auth.driver

AuthManager té el codi per als dos tipus de Guards disponibles de sèrie:

Tots els mètodes que no estiguin a Manager s'executen al default Guard:

public function __call($method, $parameters)
    {
        return $this->guard()->{$method}(...$parameters);
    }

User providers

Vegeu també

Enllaços externs