Laravel et surcharge de l’authentification

On voit plein de tutoriels qui explique comment faire pour surcharger l’authentification de Laravel. On ajoute un champ téléphone au lieu d’un email dans le validate… Mais lorsque vous voulez simplement crypter le contenu de votre base de données et donc de l’identifant (ici le mail), ca ne fonctionne plus vraiment. Voyons ensemble comment pallier aux différents problèmes qui se posent lorsque vous travaillez avec une base de données chiffrée.

Cryptage et Décryptage:

Laravel possède une classe dédiée pour cela (Illuminate\Support\Facades\Crypt). On retrouve ainsi 2 méthodes:
– Crypt::encryptString
– Crypt::decryptString

Ces 2 méthodes utilisent la clé que Laravel vous a généré dans le fichier .env (via la commande php artisan key:generate), et vous permettent de facilement manipuler les informations de la base.

Il vous suffit simplement de surcharger les accesseurs de vos modèles. Exemple:

public function setFirstname($s){
        $this->first_name = Crypt::encryptString($s);
}

public function getFirstname(){
        return Crypt::decryptString($this->first_name);
}

Pour l’instant, c’est simple, mais ca va pas tarder à changer…

Un cryptage se fait à un instant T:

Lorsque vous cryptez votre nom d’utilisateur à un autre moment de votre journée, vous n’aurez pas le même résultat. Le cryptage dépend de l’instant où vous le faites, et donc va poser un problème lorsque vous enregistrerez le mail en crypté. En effet, lorsque l’internaute souhaite se relogguer, il va saisir son mot de passe en clair. Ensuite, vous le crypter, vous obtenez donc un 2e code qui ne sera pas identique au 1er, et donc il vous sera impossible de l’authentifier. (ou alors vous passer sur tous les utilisateurs pour trouver la même valeur en la décryptant: pas génial).

Il faut donc utiliser une 2e méthode de chiffrement. J’ai passé pas mal de temps à comprendre, tout cela, donc voila grosso modo le résultat:

public static function encodeEmail($s){
$cipher = config('app.cipher', 'AES-256-CBC');
$key = config('app.key');
$iv = base64_decode(file_get_contents(app_path().'/../config/mail.key'));
return base64_encode(openssl_encrypt($s, $cipher, $key, 1, $iv));
}

public static function decodeEmail($email){
$cipher = config('app.cipher', 'AES-256-CBC');
$key = config('app.key');
$iv = base64_decode(file_get_contents(app_path().'/../config/mail.key'));
return openssl_decrypt( base64_decode($email), $cipher, $key, 1, $iv);
}

Note:
Le fichier mail.key est généré depuis un base64_encode(openssl_random_pseudo_bytes(16))

Pour reprendre notre class User, on a donc cela:

public function setEmail($s){
        $this->email  = HelperServiceProvider::encodeEmail($s);    
}

public function getEmail(){
        return HelperServiceProvider::decodeEmail($this->email);
}

L’authentification

Le login étant le mail dans la plupart des cas, en le cryptant, on vient donc de casser l’authentification. Pour réparer cela, ajoutez la fonction suivante dans Auth\LoginController.php

public function attemptLogin( $request) {
       $isUserValidated=false;
       $email = $request->input('email');
       $user = User::where("email","=",HelperServiceProvider::encodeEmail($email))->first();
   if (!empty($user)) {
           if (\Hash::check($request->password, $user->password)) {
               $isUserValidated=true;
               $this->guard()->login($user,false);
           }
       }

   return $isUserValidated;
}

Backpack:

Backpack est une interface d’administration pour vos entités assez géniale. Perso, je l’utilise dans tous mes projets. Hélas, l’authentification n’est pas forcément la même que sur Laravel. Donc même chose, il faut surcharger la fonction attemptLogin. Pour cela, j’ai créé une classe App\Http\Controllers\Admin\LoginController qui étend l’originale \Backpack\CRUD\app\Http\Controllers\Auth\LoginController; et j’ai seulement ajouté la fonction cité précédemment.

Il faut également écraser la route originale pour pointer vers notre controller.
Voici le code à ajouter dans routes/backpack/custom.php (modifiez avec vos namespace).

Route::group(
[
'namespace' => 'App\Http\Controllers\Admin',
'middleware' => config('backpack.base.web_middleware', 'web'),
'prefix' => config('backpack.base.route_prefix'),
],
function () {
// if not otherwise configured, setup the auth routes
if (config('backpack.base.setup_auth_routes')) {
Route::post('login', 'LoginController@login');
}
});

Gravatar:

Le système de Backpack se base sur Gravatar pour afficher votre photo en fonction du mail. Si vous n’en avez pas besoin, vous pouvez le désactiver via le fichier config/backpack/base.php dans ‘avatar_type’ => ‘placehold’. Mais si vous en avez besoin alors il vous faut créer un helper. Pour cela, dans le composer.json, ajouter la partie files dans l’autoload:

"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
],
"files": [
"app/Helpers/helpers.php"
]
},

Ensuite, dans le fichier helpers.php, ajouter cela:

function backpack_avatar_url($user)
{
$firstLetter = $user->getAttribute('name') ? mb_substr($user->name, 0, 1, 'UTF-8') : 'A';
$placeholder = 'https://placehold.it/160x160/00a65a/ffffff/&text='.$firstLetter;

switch (config('backpack.base.avatar_type')) {
case 'gravatar':
if (backpack_users_have_email()) {
return Gravatar::fallback('https://placehold.it/160x160/00a65a/ffffff/&text='.$firstLetter)->get($user->getEmail());
} else {
return $placeholder;
}
break;

case 'placehold':
return $placeholder;
break;

default:
return method_exists($user, config('backpack.base.avatar_type')) ? $user->{config('backpack.base.avatar_type')}() : $user->{config('backpack.base.avatar_type')};
break;
}
}

Conclusion:

Avant de devoir bosser sur une application bancaire qui nécessite de crypter toutes les informations, je n’avais jamais vraiment cherché à comprendre les différents mécanismes de l’authentification. Une fois de plus, je suis encore bluffé par tout ce que Laravel nous propose nativement. C’est complexe, mais tout est modulable, et une fois qu’on comprend le système, cela devient très simple d’en faire ce qu’on veut. Bref, j’adore ce framework !

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.