API Authentication usando Passport en Laravel

Desarrollo Web
Tags: php, laravel, passport

Passport es una dependencia de PHP que se acopla a Laravel desde la versión 5.4 para poder hacer una autenticación sin mantener el estado de la sesión en el servidor y usando tokens. Es importante si la API REST es consumida desde una aplicación móvil.

Un API es una forma de acceso a datos de un servidor, ya sea de una base de datos, un archivo o bien ejecutando alguna rutina que produzca alguna información por parte del servidor y sea enviada a un cliente, ya sea desde una aplicación móvil, web, de escritorio o cualquier tipo de cliente que pueda enviar peticiones HTTP mediante internet o una red interna (intranet).

Si bien Laravel provee un mecanismo de autenticación para las API, desde la versión 5.4 de Laravel, se introduce una librería que se acopla a Laravel para poder manejar las sesiones mediante un token llamada Passport.

Instalación del proyecto

Instalamos Laravel 5.5

composer create-project --prefer-dist laravel/laravel blog "5.5.*"

Después de la instalación, instalamos laravel\passport

composer require laravel/passport "4.0.3"

En el archivo config/app.php agregamos el Service Provider

'providers' => [
    ....

    Laravel\Passport\PassportServiceProvider::class,
],

Corremos las migraciones

php artisan migrate

Nos creará un conjunto de tablas que son usadas por Passport. Ahora, instalamos Passport

php artisan passport:install

Configuración Passport

Agregamos el Trait de HasApiTokens a nuestro modelo de usuarios

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

use Laravel\Passport\HasApiTokens;//Importamos el trait

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;//usamos el trait

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password', 'last_name', 'graduated', 'key'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
}

En app/Providers/AuthServiceProviders.php agregamos la llamada a la función Passport::routes() en la función boot

public function boot()
{ 
    $this->registerPolicies(); 
    Passport::routes(); 
}

Para terminar, cambiamos el driver de autenticación de nuestra API por passport en config/auth.php

'guards' => [
    ....

    'api' => [
        'driver' => 'passport',//aquí lo cambiamos
        'provider' => 'users',
    ],
],

Funcionalidad

En nuestro archivo de rutas routes/api.php creamos las rutas de registro y login

Route::post('login', 'UserController@login');
Route::post('register', 'UserController@register');

Creamos el controlador

php artisan make:controller UserController

Tendremos algo como esto

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    //
}

En este momento debemos hacer un login automático con el Facade Auth, como lo dice su página principal. Una vez se valida el usuario, entonces creamos un token y se enviamos al usuario para que con este, pueda ser utilizado para todas sus peticiones HTTP.

namespace Siin\Http\Controllers;

use Illuminate\Http\Request;
use App\User; 
use Illuminate\Support\Facades\Auth; 
use Validator;

class UserController extends Controller
{
    public function login()
    {
        if(Auth::attempt(['email' => request('email'), 'password' => request('password')])) {//validar que el usuario existe en la bd 
            $user = Auth::user();//obtenemos el usuario logueado
            $success['token'] =  $user->createToken('MyApp')->accessToken; //creamos el token
            return response()->json(['success' => $success], 200);//se lo enviamos al usuario
        } else {
            return response()->json(['error'=>'Unauthorised'], 401); 
        }
    }
}

Ahora, para registrar un usuario usamos Validator para validar los datos o un Request, para nuestro caso será un validator para después solo crear un usuario, su token y ser enviado al usuario.

public function register(Request $request)
{ 
    $validator = Validator::make($request->all(), [ //creamos la validación
        'name' => 'required', 
        'email' => 'required|email', 
        'password' => 'required', 
        'c_password' => 'required|same:password', 
    ]);
    if ($validator->fails()) {//validamos
        return response()->json(['error'=>$validator->errors()], 401);
    }
    
    //creamos el usuario
    $input = $request->all();
    $input['password'] = bcrypt($input['password']);
    $user = User::create($input);

    //creamos el token y se lo enviamos al usuario
    $success['token'] =  $user->createToken('MyApp')->accessToken;
    return response()->json(['success'=>$success], 200);
}

Para terminar, solo basta hacer las pruebas. En este caso usaremos Postman.

Pruebas con Postman

Creamos un usuario desde la consola con Tinker.

User::create([
    'name' => 'Luis Antonio', 
    'email' => 'luis.guillen@lungosoft.com', 
    'password' => bcrypt('prueba'),
]);

Debemos tener instalado Postman. Una vez lo hemos instalado, abrimos le programa y nos dirigimos a la ruta api/login enviando email y password.

Como vemos, recibimos un token, es el que usaremos para consultar rutas. Ahora probemos register

Como vemos, recibimos una cadena completamente diferente.

Ahora, para terminar, creemos una ruta donde obtengamos la información del usuario que está logueado

Route::midleware('auth:api')->post('details', 'UserController@details');

Vemos que agregamos el middleware auth:api para que se verifique una sesión antes de pasar al controlador.

Dentro del controlador agregamos la función

public function details() 
{ 
    $user = Auth::user(); 
    return response()->json(['success' => $user], 200); 
}

Primero, debemos agregar 3 cabeceras

  • Content-Type: application/x-www-form-urlencoded
  • Accept: application/json
  • Authorization: Bearer token

Donde la palabra token se refiere al token que hemos recibido por parte del servidor al momento de loguearnos o registrarnos.

Veamos el resultado del primer usuario

Ahora del usuario que se registro

Con esto vemos que efectivamente sirven nuestros métodos de logueo y registro.

Conclusión

Vimos una nueva manera de crear y loguar usuarios usando Passport. De esta manera, podemos crear un API con autenticación que sea accedida desde cualquier aplicación móvil, de escritorio, web, etc. En siguientes Post agregaremos como hacer unit test para API usando Passport.