Passport
Authentification et autorisation
pour API REST Laravel 5.5
L’objectif de cette suite de tutoriels sur Laravel 5.5 est de permettre au développeur Web de déployer une API REST de qualité sur le Net.
Le tutoriel sur Passport pour Laravel consiste à ajouter une couche d’authentification et d’autorisation à votre API REST. Afin de garantir la sécurité de l’API, il est essentiel de s’authentifier afin de modifier certaines ressources protégées.
Pour ce faire, le module Passport sera utilisé. Il sera donc possible d’utiliser le protocole OAuth2 (https://fr.wikipedia.org/wiki/OAuth) afin de permettre à un utilisateur d’accéder à certaines ressources. OAuth est le protocole d’authentification privilégié par Google et Facebook.
Passport offre plusieurs méthodes d’authentification, celle qui nous intéresse se nomme Password grant. Elle permettra à un utilisateur d’obtenir un jeton d’accès (access token) après avoir soumis un courriel et un mot de passe valides.
Récits utilisateur proposés
- En tant qu’utilisateur, j’aimerais gérer (CRUD) mes stations.
- En tant qu’utilisateur, j’aimerais être le seul à pouvoir modifier (PUT) et supprimer (DELETE) mes stations (OwnerMiddleware).
- En tant que citoyen, j’aimerais avoir accès à la liste des stations (GET).
- En tant que citoyen, j’aimerais avoir accès aux informations d’une station (GET).
- En tant qu’utilisateur connecté, j’aimerais avoir accès aux informations de mon profil et de mon compte utilisateur (GET).
Plan de match pour ce tutoriel
- Lire le code en annexe.
- Installer Passport.
- Ajouter une nouvelle route protégée.
- Tester la nouvelle fonctionnalité.
- Publier sur GitLab.
- Publier sur Heroku.
Prérequis :
- Projet configuré avec GitLab et Heroku.
- Créer un modèle User.
- Créer une migration pour le modèle User.
- Créer des données de tests (seed) pour la table utilisateur (UsersTableSeeder).
Lectures proposées :
- https://laravel.com/docs/5.5/passport
- https://laravel.com/docs/5.5/passport#password-grant-tokens
Installer Passport pour Laravel
Lors du processus, l’API pourrait se retrouver dans un état « non fonctionnel ». Il est donc recommandé de créer une nouvelle branche pour l’expérimentation avec Passport. Si l’objectif est atteint, vous pourrez ensuite faire un merge sur master.
$ git chechout -b « Lab 7 – Auth with Passport »
Résumé des étapes
Suivre la documentation officielle :
https://laravel.com/docs/5.5/passport#installation
$ composer require laravel/passport
$ php artisan migrate:fresh –seed
$ php artisan passport:install
Modifier App\User en y ajoutant le trait Laravel\Passport\HasApiTokens
Ajouter Passport::routes dans la méthode boot de la classe AuthServiceProvider
Modifier config/auth.php et changer le driver pour le guard api ‘driver’ => ‘passport’
$ php artisan route:list
Prendre une pause
La position assise est très dommageable pour la santé. De plus, regarder un écran pendant plus de 20 minutes est aussi mauvais. Prenez le temps de vous lever et de vous étirer durant 45 secondes. Prenez aussi conscience de la position de votre corps lorsque vous travaillez.
Le Personal Grant Token
Nous allons maintenant explorer le Personal token. La première étape consiste à créer un client et par la suite créer un User basé sur ce nouveau client. Une fois le User créé, vous aurez accès à son jeton. Ce jeton sera utilisé pour accéder à des ressources protégées.
Créer un client
Lancer la commande suivante afin de créer un nouveau client de type personnel :
$ php artisan passport:client –personal –name=iot
Route pour la génération de jeton (api.php)
Ajouter la route suivante et l’afficher dans le navigateur.
Route::get(‘/create-personal-token‘, function () {
$rnd = random_int(0, 1000);
$user = new App\User();
$user->name = $rnd.’oauth’;
$user->password = Hash::make(‘secret’);
$user->email = $rnd.’oauth@mail.com’;
$user->save();
$token = $user->createToken(‘iot’)->accessToken;
echo $token;
});
Protéger des routes avec le middlerare auth:api
Une fois la route configurée avec le middleware auth:api, vous devrez utiliser le jeton de l’utilisateur afin d’accéder à la ressource. Sans ce jeton, une erreur 401 sera retournée.
Fichier api.php
Route::middleware(‘auth:api’)->get(‘/user’, function (Request $request) {
return $request->user();
});
Route::middleware(‘auth:api’)->get(‘/user/profile’, function (Request $request) {
return $request->user()->profile;
});
Utiliser le jeton pour accéder à une route protégée
Afficher l’URL suivante pour récupérer le jeton :
- http://monapp.quebec/api/create-personal-token
Copier le jeton et l’ajouter dans Postman pour tenter l’accès à la nouvelle route /api/user
- GET http://monapp.quebec/api/user
En-têtes :
Content-Type application/json
Accept application/json
Quel est le code retourné?
Modifier la requête en ajoutant l’en-tête Authorization
- GET http://monapp.quebec/api/user
En-têtes :
Content-Type: application/json
Accept: application/json
Authorization Bearer iJKV1QiLCJh………….bNiIsImp0aSI
Bravo, vous pouvez maintenant sécuriser les ressources de votre API !
Faire un commit pour sauvegarder vos changements.
Protéger une route avec le owner middleware
Le middleware est une couche logicielle appliquée avant d’atteindre l’action de votre contrôleur. Le middleware que je vous propose de créer permettra de vérifier que l’utilisateur est bien le propriétaire d’une ressource. Si ce n’est pas le cas, un code de statut 403 sera lancé et l’action ne sera pas exécutée.
# créer une nouvelle branche pour le owner middleware.
$ php artisan make:middleware AbortIfNotOwnerMiddleware
Voir le code : Annexe 1 : Middleware AbortIfNotOwner
Enregistrer la classe dans le fichier App/Http/Kernel.php
‘owner’ => \App\Http\Middleware\AbortIfNotOwner::class,
Ajouter les routes fournies à la page suivante.
Attention, le nom de la ressource dans la route {stations} doit correspondre au nom de la ressource spécifiée pour le middleware ‘owner:stations’.
Route::put(‘stations/{stations}’, ‘StationController@update’)
->middleware([‘auth:api’, ‘owner:stations’]);
Ajout du middleware owner:stations [routes/api.php]
Configurer les routes pour bénéficier du middleware.
Public
Route::get(‘stations/{station}’, ‘StationController@show’);
Route::get(‘stations’, ‘StationController@index’);
Protégé
Route::post(‘stations’, ‘StationController@store’)->middleware([‘auth:api’]);
Route::middleware(‘auth:api’)->get(‘/user’, function (Request $request) {
return $request->user();
});
Protégé avec vérification du propriétaire (owner)
Route::delete(‘stations/{stations}’, ‘StationController@destroy’)
->middleware([‘auth:api’, ‘owner:stations’]);
Route::put(‘stations/{stations}’, ‘StationController@update’)
->middleware([‘auth:api’, ‘owner:stations’]);
Le Password Grant Token
Le password grant token permet à un utilisateur de récupérer un jeton lorsqu’il s’authentifie avec son courriel et son mot de passe.
Créer un nouveau client
Créer un nouveau client avec authentification par mot de passe :
$ php artisan passport:client –password –name=password_client
What should we name the password grant client?
[RevolvAir API Password Grant Client]:
Password grant client created successfully.
Client ID: 3
Client Secret: bPRYtiyG0mUKaGtfvxNQLVjq5tVSMPX83geYWx4h
Requête pour récupérer le jeton
Lancer une requête POST vers la route /oauth/token avec la configuration suivante :
Dans POSTMAN, utiliser x-www-form-urlencoded avec les données suivantes :
grant_type password
client_id 3
client_secret bPRYtiyG0mUKaGtfvxNQLVjq5tVSMPX83geYWx4h
username admin@email.quebec # courriel défini dans votre fichier seed
password admin # mot de passe défini dans votre fichier seed
scope *
Récupérer le jeton avec cURL
$ sudo apt-get install curl
$ curl -d grant_type=password -d client_id=1 -d client_secret=cmB8TpsquFuOnAYF46S8pymJtV1BteDRSQiG8UiI -d username=tech@email.com -d password=tech -d scope=* http://localhost:8000/oauth/token
Récupérer le jeton avec Postman
Si tout fonctionne bien, une réponse avec jeton vous sera retournée :
{
« token_type »: « Bearer »,
« expires_in »: 31536000,
« access_token »: « eyJ0eXAiOiJKV1QiLCJhbGciOiJSU..OiJSU. »,
« refresh_token »: « def50200555b4d77dfdb1b98b34b…b98b34b »
}
Utiliser le jeton – L’en-tête Authorization
Finalement, utiliser le jeton afin de lancer une requête vers la ressource protégée.
$response = $client->request(‘GET’, ‘/api/user’, [
‘headers’ => [
‘Accept’ => ‘application/json’,
‘Authorization’ => ‘Bearer ‘.$accessToken,
],
]);
Il faut donc définir l’en-tête Authorization avec la valeur « Bearer » concaténée avec le jeton d’accès. Notez l’espace entre Bearer et le jeton.
Tester les nouvelles fonctionnalités
Tester le bon fonctionnement du système d’authentification. Il faut donc s’assurer qu’un utilisateur non authentifié (sans jeton d’accès valide) ne pourra accéder à la ressource protégée.
Cas de tests à considérer :
- GET avec jeton d’accès valide – 200
- GET sans jeton d’accès – 401
- GET pour une ressource qui appartient à un autre utilisateur (owner) – 403
- PUT sur une station dont vous n’êtes pas propriétaire – Test du middleware.
- Encore une fois, il faut vérifier les codes de statut retournés par l’API REST.
Tester avec Passport ::ActingAs
Afin d’interagir avec le système sous une identifié particulière, vous pouvez utiliser ActingAs. Cela vous permettra de simuler des utilisateurs anonymes, authentifiés, propriétaires ou non propriétaires d’une ressource.
use Laravel\Passport\Passport;
public function testServerCreation()
{
Passport::actingAs( \App\User::find(1));
$response = $this->post(‘/api/create-server’);
$response->assertStatus(200);
}
Voici quelques vérifications (assert) sont pour faciliter vos tests :
# Vérifie qu’un message relié au courriel est bien retourné :
$response->assertJsonValidationErrors(’email’);
# Vérifie que la requête est un succès :
$response->assertSuccessful();
Écrire les tests et lancer les tests :
$ vendor/phpunit/phpunit/phpunit
Références sur les tests avec Passport :
- https://laravel.com/docs/5.5/passport#testing
- https://laravel.com/docs/5.5/http-tests#testing-json-apis
Réusinage
Prenez quelques minutes afin de vérifier les fichiers modifiés et ajoutés. Un petit ménage s’impose peut-être.
$ git status
Publier sur Gitlab et Heroku
Finalement, faire un merge sur master et publier votre travail sur GitLab.
$ git add .
$ git commit -m « Lab 7 – Passport Auth with tests and Owner Middlerare »
$ git push
$ git push heroku master
Annexe 1 : Middleware AbortIfNotOwner
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class AbortIfNotOwner
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $resourceName
* @return mixed
*/
public function handle($request, Closure $next, $resourceName)
{
// Sans implicit binding
// $resourceId = $request->route()->parameter($resourceName);
// $user_id = \DB::table($resourceName)->find($resourceId)->user_id;
// Avec implicit binding
$resource = $request->route()->parameter($resourceName);
// Aide au débogage
// echo json_encode(Auth::check());
// echo json_encode(Auth::user()->id);
// echo json_encode($resource->user_id);
// exit();
if (Auth::check() == false || Auth::user()->id != $resource->user_id) {
abort(403, ‘Unauthorized action.’);
}
return $next($request);
}
}
Annexe 2 : Modèle User
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [ ‘name’, ’email’, ‘password’, ];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [ ‘password’, ‘remember_token’, ];
}
Annexe 3 : Migration pour la table User
public function up()
{
Schema::create(‘users’, function (Blueprint $table) {
$table->increments(‘id’);
$table->string(‘name’);
$table->string(’email’)->unique();
$table->string(‘password’);
$table->string(‘avatar’)->default(‘default_avatar.jpg’);
$table->timestamps();
$table->softDeletes();
$table->rememberToken();
});
}
Annexe 4 : Seed pour la table User
…
public function run()
{
User::create(
array(
‘name’ => ‘admin’,
’email’ => ‘admin@admin.org’,
‘password’ => Hash::make(‘admin’),
)
);
}
…
Bravo!
Bravo, votre environnement de développement avec Homestead, Vagrant, PHP, MySQL est fonctionnel.
Configurons une application qui utilise le cadriciel Laravel.
Références et lectures
- https://www.getpostman.com/
- https://github.com/symfony/symfony/
- https://vagrantup.com/downloads.html
Déployer votre API REST Laravel 5.5
L’étape finale consiste à déployer votre projet Web avec l’hébergeur Heroku.
Facebook Comments