() translation by (you can also view the original English article)
Dans cet article, nous allons couvrir le système d’authentification dans le framework Laravel. L'objectif principal de cet article est de créer une protection d'authentification personnalisée en étendant le système d'authentification principal.
Laravel fournit un système d'authentification très solide dans le noyau qui facilite grandement la mise en œuvre de l'authentification de base. En fait, il vous suffit d'exécuter quelques commandes artisanales pour configurer l'échafaudage d'un système d'authentification.
De plus, le système lui-même est conçu de manière à pouvoir être étendu et connecté à vos adaptateurs d’authentification personnalisés. C’est ce dont nous discuterons en détail tout au long de cet article. Avant de nous lancer dans l’implémentation de la protection d’authentification personnalisée, nous commencerons par une discussion des éléments de base du système d’authentification Laravel, à savoir les gardes et les fournisseurs.
Les éléments fondamentaux: gardes et fournisseurs
Le système d'authentification Laravel est composé de deux éléments principaux: les gardes et les fournisseurs.
Gardes
Vous pourriez penser à une protection comme un moyen de fournir la logique utilisée pour identifier les utilisateurs authentifiés. Dans le noyau, Laravel fournit différents gardes comme session et jeton. Le gardien de session maintient l'état de l'utilisateur dans chaque demande par le biais de cookies. D'autre part, le gardien de jeton authentifie l'utilisateur en vérifiant un jeton valide dans chaque demande.
Ainsi, comme vous pouvez le constater, le service de garde définit la logique de l’authentification et il n’est pas nécessaire qu’il traite toujours de cette information en récupérant des informations d’identification valides du serveur principal. Vous pouvez implémenter une protection qui vérifie simplement la présence d'une chose spécifique dans les en-têtes de demande et authentifie les utilisateurs en fonction de cela.
Plus loin dans cet article, nous allons implémenter une protection qui vérifie certains paramètres JSON dans les en-têtes de requête et récupère l'utilisateur valide à partir du back-end de MongoDB.
Fournisseurs
Si la protection définit la logique d'authentification, le fournisseur d'authentification est chargé de récupérer l'utilisateur à partir du stockage principal. Si la protection exige que l'utilisateur soit validé par rapport au stockage principal, la mise en œuvre de la récupération de l'utilisateur passe par le fournisseur d'authentification.
Laravel est livré avec deux fournisseurs d'authentification par défaut, Base de données et Eloquent. Le fournisseur d'authentification de base de données traite de l'extraction directe des informations d'identification de l'utilisateur depuis le stockage principal, tandis qu'Eloquent fournit une couche d'abstraction qui répond aux besoins.
Dans notre exemple, nous allons implémenter un fournisseur d'authentification MongoDB qui récupère les informations d'identification de l'utilisateur à partir du backend MongoDB.
C'était donc une introduction de base aux gardes et aux fournisseurs dans le système d'authentification Laravel. À partir de la section suivante, nous nous concentrerons sur le développement de la protection et du fournisseur d’authentification personnalisés!
Un coup d'œil sur la configuration du fichier
Examinons rapidement la liste des fichiers que nous allons implémenter tout au long de cet article.
-
config/auth.php
: C'est le fichier de configuration de l'authentification dans lequel nous ajouterons une entrée de notre garde personnalisée -
config / mongo.php
: C'est le fichier qui contient la configuration de MongoDB. -
app/Services/Contracts/NosqlServiceInterface.php
: Il s'agit d'une interface implémentée par notre classe de base de données Mongo personnalisée. -
app/Database/MongoDatabase.php
: Il s'agit d'une classe de base de données principale qui interagit avec MongoDB. -
app/Models/Auth/User.php
: Il s'agit de la classe de modèle User qui implémente le contrat Authenticable. -
app/Extensions/MongoUserProvider.php
: Il s'agit d'une implémentation du fournisseur d'authentification. -
app/Services/Auth/JsonGuard.php
: C'est une implémentation du pilote de protection d'authentification. -
app/Providers/AuthServiceProvider.php
: Il s'agit d'un fichier existant que nous utiliserons pour ajouter nos liaisons de conteneur de service. -
app/Http/Controllers/MongoController.php
: C'est un fichier de contrôleur de démonstration que nous allons implémenter pour tester notre garde personnalisée.
Ne vous inquiétez pas si la liste des fichiers n'a pas encore beaucoup de sens, car nous allons en discuter en détail.
Plongez dans l'implémentation
Dans cette section, nous allons passer en revue la mise en œuvre des fichiers requis.
La première chose à faire est d'informer Laravel de notre garde sur mesure. Allez-y et entrez les détails de la garde personnalisée dans le fichier config/auth.php
comme indiqué.
1 |
...
|
2 |
...
|
3 |
'guards' => [ |
4 |
'web' => [ |
5 |
'driver' => 'session', |
6 |
'provider' => 'users', |
7 |
],
|
8 |
|
9 |
'api' => [ |
10 |
'driver' => 'token', |
11 |
'provider' => 'users', |
12 |
],
|
13 |
|
14 |
'custom' => [ |
15 |
'driver' => 'json', |
16 |
'provider' => 'mongo', |
17 |
],
|
18 |
],
|
19 |
...
|
20 |
...
|
Comme vous pouvez le constater, nous avons ajouté notre garde personnalisée sous la clé personnalisée.
Ensuite, nous devons ajouter une entrée de fournisseur associé dans la section des fournisseurs.
1 |
...
|
2 |
...
|
3 |
'providers' => [ |
4 |
'users' => [ |
5 |
'driver' => 'eloquent', |
6 |
'model' => App\User::class, |
7 |
],
|
8 |
'mongo' => [ |
9 |
'driver' => 'mongo' |
10 |
],
|
11 |
|
12 |
// 'users' => [
|
13 |
// 'driver' => 'database',
|
14 |
// 'table' => 'users',
|
15 |
// ],
|
16 |
],
|
17 |
...
|
18 |
...
|
Nous avons ajouté l'entrée de notre fournisseur sous la clé Mongo.
Enfin, modifions la protection d'authentification par défaut de Web à personnalisée.
1 |
...
|
2 |
...
|
3 |
'defaults' => [ |
4 |
'guard' => 'custom', |
5 |
'passwords' => 'users', |
6 |
],
|
7 |
...
|
8 |
...
|
Bien sûr, cela ne fonctionnera pas encore car nous n’avons pas encore implémenté les fichiers nécessaires. Et c'est ce que nous discuterons dans les deux prochaines sections.
Configurer le pilote MongoDB
Dans cette section, nous allons implémenter les fichiers nécessaires qui parlent à l’instance MongoDB sous-jacente.
Commençons par créer un fichier de configuration config/mongo.php
contenant les paramètres de connexion par défaut de MongoDB.
1 |
<?php
|
2 |
return [ |
3 |
'defaults' => [ |
4 |
'host' => '{HOST_IP}', |
5 |
'port' => '{HOST_PORT}', |
6 |
'database' => '{DB_NAME}' |
7 |
]
|
8 |
];
|
Bien sûr, vous devez modifier les valeurs d’espace réservé conformément à vos paramètres.
Au lieu de créer directement une classe qui interagit avec MongoDB, nous allons créer une interface en premier lieu.
L'avantage de créer une interface est qu'elle fournit un contrat qu'un développeur doit respecter lors de sa mise en œuvre. De plus, notre implémentation de MongoDB pourrait être facilement remplacée par une autre implémentation NoSQL si nécessaire.
Créez ensuite un fichier d'interface app/Services/Contracts/NosqlServiceInterface.php
avec le contenu suivant.
1 |
<?php
|
2 |
// app/Services/Contracts/NosqlServiceInterface.php
|
3 |
namespace App\Services\Contracts; |
4 |
|
5 |
Interface NosqlServiceInterface |
6 |
{
|
7 |
/**
|
8 |
* Create a Document
|
9 |
*
|
10 |
* @param string $collection Collection/Table Name
|
11 |
* @param array $document Document
|
12 |
* @return boolean
|
13 |
*/
|
14 |
public function create($collection, Array $document); |
15 |
|
16 |
/**
|
17 |
* Update a Document
|
18 |
*
|
19 |
* @param string $collection Collection/Table Name
|
20 |
* @param mix $id Primary Id
|
21 |
* @param array $document Document
|
22 |
* @return boolean
|
23 |
*/
|
24 |
public function update($collection, $id, Array $document); |
25 |
|
26 |
/**
|
27 |
* Delete a Document
|
28 |
*
|
29 |
* @param string $collection Collection/Table Name
|
30 |
* @param mix $id Primary Id
|
31 |
* @return boolean
|
32 |
*/
|
33 |
public function delete($collection, $id); |
34 |
|
35 |
/**
|
36 |
* Search Document(s)
|
37 |
*
|
38 |
* @param string $collection Collection/Table Name
|
39 |
* @param array $criteria Key-value criteria
|
40 |
* @return array
|
41 |
*/
|
42 |
public function find($collection, Array $criteria); |
43 |
}
|
C'est une interface assez simple qui déclare les méthodes de base CRUD qu'une classe doit définir pour implémenter cette interface.
Maintenant, définissons une classe réelle à app/Database/MongoDatabase.php
.
1 |
<?php
|
2 |
// app/Database/MongoDatabase.php
|
3 |
namespace App\Database; |
4 |
|
5 |
use App\Services\Contracts\NosqlServiceInterface; |
6 |
|
7 |
class MongoDatabase implements NosqlServiceInterface |
8 |
{
|
9 |
private $connection; |
10 |
private $database; |
11 |
|
12 |
public function __construct($host, $port, $database) |
13 |
{
|
14 |
$this->connection = new MongoClient( "mongodb://{$host}:{$port}" ); |
15 |
$this->database = $this->connection->{$database}; |
16 |
}
|
17 |
|
18 |
/**
|
19 |
* @see \App\Services\Contracts\NosqlServiceInterface::find()
|
20 |
*/
|
21 |
public function find($collection, Array $criteria) |
22 |
{
|
23 |
return $this->database->{$collection}->findOne($criteria); |
24 |
}
|
25 |
|
26 |
public function create($collection, Array $document) {} |
27 |
public function update($collection, $id, Array $document) {} |
28 |
public function delete($collection, $id) {} |
29 |
}
|
Bien entendu, je suppose que vous avez installé MongoDB et l’extension PHP MongoDB correspondante.
La méthode __construct
instancie la classe MongoClient
avec les paramètres nécessaires. L'autre méthode importante qui nous intéresse est la méthode find
, qui récupère l'enregistrement en fonction des critères fournis en tant qu'arguments de la méthode.
C’était donc l’implémentation du pilote MongoDB et j’ai essayé de le garder le plus simple possible.
Configurer le modèle utilisateur
Conformément aux normes du système d'authentification, nous devons implémenter le modèle utilisateur qui doit implémenter le contrat Illuminate\Contracts\Auth\Authenticatable
.
Allez-y et créez un fichier app/Models/Auth/User.php
avec le contenu suivant.
1 |
<?php
|
2 |
// app/Models/Auth/User.php
|
3 |
namespace App\Models\Auth; |
4 |
|
5 |
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; |
6 |
use App\Services\Contracts\NosqlServiceInterface; |
7 |
|
8 |
class User implements AuthenticatableContract |
9 |
{
|
10 |
private $conn; |
11 |
|
12 |
private $username; |
13 |
private $password; |
14 |
protected $rememberTokenName = 'remember_token'; |
15 |
|
16 |
public function __construct(NosqlServiceInterface $conn) |
17 |
{
|
18 |
$this->conn = $conn; |
19 |
}
|
20 |
|
21 |
/**
|
22 |
* Fetch user by Credentials
|
23 |
*
|
24 |
* @param array $credentials
|
25 |
* @return Illuminate\Contracts\Auth\Authenticatable
|
26 |
*/
|
27 |
public function fetchUserByCredentials(Array $credentials) |
28 |
{
|
29 |
$arr_user = $this->conn->find('users', ['username' => $credentials['username']]); |
30 |
|
31 |
if (! is_null($arr_user)) { |
32 |
$this->username = $arr_user['username']; |
33 |
$this->password = $arr_user['password']; |
34 |
}
|
35 |
|
36 |
return $this; |
37 |
}
|
38 |
|
39 |
/**
|
40 |
* {@inheritDoc}
|
41 |
* @see \Illuminate\Contracts\Auth\Authenticatable::getAuthIdentifierName()
|
42 |
*/
|
43 |
public function getAuthIdentifierName() |
44 |
{
|
45 |
return "username"; |
46 |
}
|
47 |
|
48 |
/**
|
49 |
* {@inheritDoc}
|
50 |
* @see \Illuminate\Contracts\Auth\Authenticatable::getAuthIdentifier()
|
51 |
*/
|
52 |
public function getAuthIdentifier() |
53 |
{
|
54 |
return $this->{$this->getAuthIdentifierName()}; |
55 |
}
|
56 |
|
57 |
/**
|
58 |
* {@inheritDoc}
|
59 |
* @see \Illuminate\Contracts\Auth\Authenticatable::getAuthPassword()
|
60 |
*/
|
61 |
public function getAuthPassword() |
62 |
{
|
63 |
return $this->password; |
64 |
}
|
65 |
|
66 |
/**
|
67 |
* {@inheritDoc}
|
68 |
* @see \Illuminate\Contracts\Auth\Authenticatable::getRememberToken()
|
69 |
*/
|
70 |
public function getRememberToken() |
71 |
{
|
72 |
if (! empty($this->getRememberTokenName())) { |
73 |
return $this->{$this->getRememberTokenName()}; |
74 |
}
|
75 |
}
|
76 |
|
77 |
/**
|
78 |
* {@inheritDoc}
|
79 |
* @see \Illuminate\Contracts\Auth\Authenticatable::setRememberToken()
|
80 |
*/
|
81 |
public function setRememberToken($value) |
82 |
{
|
83 |
if (! empty($this->getRememberTokenName())) { |
84 |
$this->{$this->getRememberTokenName()} = $value; |
85 |
}
|
86 |
}
|
87 |
|
88 |
/**
|
89 |
* {@inheritDoc}
|
90 |
* @see \Illuminate\Contracts\Auth\Authenticatable::getRememberTokenName()
|
91 |
*/
|
92 |
public function getRememberTokenName() |
93 |
{
|
94 |
return $this->rememberTokenName; |
95 |
}
|
96 |
}
|
Vous devriez déjà avoir remarqué que
App\Models\Auth\User
implémente le contrat Illuminate\Contracts\Auth\Authenticatable
.
La plupart des méthodes mises en œuvre dans notre classe s'expliquent d'elles-mêmes. Cela dit, nous avons défini la méthode fetchUserByCredentials
, qui extrait l'utilisateur du back-end disponible. Dans notre cas, ce sera une classe MongoDatabase
qui sera appelée pour récupérer les informations nécessaires.
Voilà donc la mise en œuvre du modèle utilisateur.
Configurer le fournisseur d'authentification
Comme nous l'avons vu précédemment, le système d'authentification Laravel est constitué de deux éléments: les gardes et les fournisseurs.
Dans cette section, nous allons créer un fournisseur d'authentification qui traite de la récupération des utilisateurs à partir du serveur principal.
Allez-y et créez un fichier app/Extensions/MongoUserProvider.php
comme indiqué ci-dessous.
1 |
<?php
|
2 |
// app/Extensions/MongoUserProvider.php
|
3 |
namespace App\Extensions; |
4 |
|
5 |
use Illuminate\Support\Str; |
6 |
use Illuminate\Contracts\Auth\UserProvider; |
7 |
use Illuminate\Contracts\Auth\Authenticatable; |
8 |
|
9 |
class MongoUserProvider implements UserProvider |
10 |
{
|
11 |
/**
|
12 |
* The Mongo User Model
|
13 |
*/
|
14 |
private $model; |
15 |
|
16 |
/**
|
17 |
* Create a new mongo user provider.
|
18 |
*
|
19 |
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
20 |
* @return void
|
21 |
*/
|
22 |
public function __construct(\App\Models\Auth\User $userModel) |
23 |
{
|
24 |
$this->model = $userModel; |
25 |
}
|
26 |
|
27 |
/**
|
28 |
* Retrieve a user by the given credentials.
|
29 |
*
|
30 |
* @param array $credentials
|
31 |
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
32 |
*/
|
33 |
public function retrieveByCredentials(array $credentials) |
34 |
{
|
35 |
if (empty($credentials)) { |
36 |
return; |
37 |
}
|
38 |
|
39 |
$user = $this->model->fetchUserByCredentials(['username' => $credentials['username']]); |
40 |
|
41 |
return $user; |
42 |
}
|
43 |
|
44 |
/**
|
45 |
* Validate a user against the given credentials.
|
46 |
*
|
47 |
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
48 |
* @param array $credentials Request credentials
|
49 |
* @return bool
|
50 |
*/
|
51 |
public function validateCredentials(Authenticatable $user, Array $credentials) |
52 |
{
|
53 |
return ($credentials['username'] == $user->getAuthIdentifier() && |
54 |
md5($credentials['password']) == $user->getAuthPassword()); |
55 |
}
|
56 |
|
57 |
public function retrieveById($identifier) {} |
58 |
|
59 |
public function retrieveByToken($identifier, $token) {} |
60 |
|
61 |
public function updateRememberToken(Authenticatable $user, $token) {} |
62 |
}
|
Là encore, vous devez vous assurer que le fournisseur personnalisé doit implémenter le contrat Illuminate\Contracts\Auth\UserProvider
.
Pour aller de l'avant, il définit deux méthodes importantes: retrieveByCredentials et validateCredentials.
La méthode retrieveByCredentials
permet de récupérer les informations d'identification de l'utilisateur à l'aide de la classe de modèle User décrite dans la section précédente. D'autre part, la méthode validateCredentials
est utilisée pour valider un utilisateur par rapport à l'ensemble d'identifiants donné.
Et ce fut la mise en œuvre de notre fournisseur d'authentification personnalisé. Dans la section suivante, nous allons créer une protection qui interagit avec le fournisseur d'authentification MongoUserProvider
.
Configurer la garde d'authentification
Comme nous en avons discuté précédemment, le système de protection du système d’authentification de Laravel définit le mode d’authentification de l’utilisateur. Dans notre cas, nous vérifierons la présence du paramètre de requête jsondata qui devrait contenir la chaîne codée JSON des informations d'identification.
Dans cette section, nous allons créer une protection qui interagit avec le fournisseur d'authentification créé dans la dernière section.
Allez-y et créez un fichier app/Services/Auth/JsonGuard.php
avec le contenu suivant.
1 |
<?php
|
2 |
// app/Services/Auth/JsonGuard.php
|
3 |
namespace App\Services\Auth; |
4 |
|
5 |
use Illuminate\Http\Request; |
6 |
use Illuminate\Contracts\Auth\Guard; |
7 |
use Illuminate\Contracts\Auth\UserProvider; |
8 |
use GuzzleHttp\json_decode; |
9 |
use phpDocumentor\Reflection\Types\Array_; |
10 |
use Illuminate\Contracts\Auth\Authenticatable; |
11 |
|
12 |
class JsonGuard implements Guard |
13 |
{
|
14 |
protected $request; |
15 |
protected $provider; |
16 |
protected $user; |
17 |
|
18 |
/**
|
19 |
* Create a new authentication guard.
|
20 |
*
|
21 |
* @param \Illuminate\Contracts\Auth\UserProvider $provider
|
22 |
* @param \Illuminate\Http\Request $request
|
23 |
* @return void
|
24 |
*/
|
25 |
public function __construct(UserProvider $provider, Request $request) |
26 |
{
|
27 |
$this->request = $request; |
28 |
$this->provider = $provider; |
29 |
$this->user = NULL; |
30 |
}
|
31 |
|
32 |
/**
|
33 |
* Determine if the current user is authenticated.
|
34 |
*
|
35 |
* @return bool
|
36 |
*/
|
37 |
public function check() |
38 |
{
|
39 |
return ! is_null($this->user()); |
40 |
}
|
41 |
|
42 |
/**
|
43 |
* Determine if the current user is a guest.
|
44 |
*
|
45 |
* @return bool
|
46 |
*/
|
47 |
public function guest() |
48 |
{
|
49 |
return ! $this->check(); |
50 |
}
|
51 |
|
52 |
/**
|
53 |
* Get the currently authenticated user.
|
54 |
*
|
55 |
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
56 |
*/
|
57 |
public function user() |
58 |
{
|
59 |
if (! is_null($this->user)) { |
60 |
return $this->user; |
61 |
}
|
62 |
}
|
63 |
|
64 |
/**
|
65 |
* Get the JSON params from the current request
|
66 |
*
|
67 |
* @return string
|
68 |
*/
|
69 |
public function getJsonParams() |
70 |
{
|
71 |
$jsondata = $this->request->query('jsondata'); |
72 |
|
73 |
return (!empty($jsondata) ? json_decode($jsondata, TRUE) : NULL); |
74 |
}
|
75 |
|
76 |
/**
|
77 |
* Get the ID for the currently authenticated user.
|
78 |
*
|
79 |
* @return string|null
|
80 |
*/
|
81 |
public function id() |
82 |
{
|
83 |
if ($user = $this->user()) { |
84 |
return $this->user()->getAuthIdentifier(); |
85 |
}
|
86 |
}
|
87 |
|
88 |
/**
|
89 |
* Validate a user's credentials.
|
90 |
*
|
91 |
* @return bool
|
92 |
*/
|
93 |
public function validate(Array $credentials=[]) |
94 |
{
|
95 |
if (empty($credentials['username']) || empty($credentials['password'])) { |
96 |
if (!$credentials=$this->getJsonParams()) { |
97 |
return false; |
98 |
}
|
99 |
}
|
100 |
|
101 |
$user = $this->provider->retrieveByCredentials($credentials); |
102 |
|
103 |
if (! is_null($user) && $this->provider->validateCredentials($user, $credentials)) { |
104 |
$this->setUser($user); |
105 |
|
106 |
return true; |
107 |
} else { |
108 |
return false; |
109 |
}
|
110 |
}
|
111 |
|
112 |
/**
|
113 |
* Set the current user.
|
114 |
*
|
115 |
* @param Array $user User info
|
116 |
* @return void
|
117 |
*/
|
118 |
public function setUser(Authenticatable $user) |
119 |
{
|
120 |
$this->user = $user; |
121 |
return $this; |
122 |
}
|
123 |
}
|
Tout d’abord, notre classe doit implémenter l’interface Illuminate\Contracts\Auth\Guard
. Il faut donc définir toutes les méthodes déclarées dans cette interface.
Il est important de noter ici que la fonction __construct
nécessite une implémentation de Illuminate\Contracts \Auth\UserProvider
. Dans notre cas, nous allons passer une instance de App\Extensions\MongoUserProvider
, comme nous le verrons dans la section ultérieure.
Ensuite, il existe une fonction getJsonParams
qui récupère les informations d'identification de l'utilisateur à partir du paramètre de requête nommé jsondata
. Comme nous nous attendons à recevoir une chaîne codée JSON des informations d'identification de l'utilisateur, nous avons utilisé la fonction json_decode
pour décoder les données JSON.
Dans la fonction validate, la première chose que nous vérifions est l’existence de l’argument $credentials
. S'il n'est pas présent, nous appelons la méthode getJsonParams
pour récupérer les informations d'identification de l'utilisateur à partir des paramètres de la demande.
Ensuite, nous appelons la méthode retrieveByCredentials
du fournisseur MongoUserProvider
qui extrait l'utilisateur à partir de la base de données MongoDB. Enfin, c'est la méthode validateCredentials
du fournisseur MongoUserProvider
qui vérifie la validité de l'utilisateur.
C'était donc la mise en œuvre de notre garde de douane. La section suivante explique comment assembler ces éléments pour former un système d’authentification réussi.
Mettre tous ensemble
Jusqu'à présent, nous avons développé tous les éléments de la protection d'authentification personnalisée qui devrait nous fournir un nouveau système d'authentification. Cependant, cela ne fonctionnera pas immédiatement car nous devons d'abord l'enregistrer à l'aide des liaisons du conteneur de services Laravel.
Comme vous le savez sûrement déjà, le fournisseur de services Laravel est le bon endroit pour mettre en œuvre les liaisons nécessaires.
Allez-y et ouvrez le fichier app/Providers/AuthServiceProvider.php
qui nous permet d’ajouter des liaisons de conteneur de service d’authentification. S'il ne contient aucune modification personnalisée, vous pouvez simplement le remplacer par le contenu suivant.
1 |
<?php
|
2 |
// app/Providers/AuthServiceProvider.php
|
3 |
namespace App\Providers; |
4 |
|
5 |
use Illuminate\Support\Facades\Auth; |
6 |
use Illuminate\Support\Facades\Gate; |
7 |
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; |
8 |
use App\Services\Auth\JsonGuard; |
9 |
use App\Extensions\MongoUserProvider; |
10 |
use App\Database\MongoDatabase; |
11 |
use App\Models\Auth\User; |
12 |
use Illuminate\Http\Request; |
13 |
use Illuminate\Support\Facades\Config; |
14 |
|
15 |
class AuthServiceProvider extends ServiceProvider |
16 |
{
|
17 |
/**
|
18 |
* The policy mappings for the application.
|
19 |
*
|
20 |
* @var array
|
21 |
*/
|
22 |
protected $policies = [ |
23 |
'App\Model' => 'App\Policies\ModelPolicy', |
24 |
];
|
25 |
|
26 |
/**
|
27 |
* Register any authentication / authorization services.
|
28 |
*
|
29 |
* @return void
|
30 |
*/
|
31 |
public function boot() |
32 |
{
|
33 |
$this->registerPolicies(); |
34 |
|
35 |
$this->app->bind('App\Database\MongoDatabase', function ($app) { |
36 |
return new MongoDatabase(config('mongo.defaults.host'), config('mongo.defaults.port'), config('mongo.defaults.database')); |
37 |
});
|
38 |
|
39 |
$this->app->bind('App\Models\Auth\User', function ($app) { |
40 |
return new User($app->make('App\Database\MongoDatabase')); |
41 |
});
|
42 |
|
43 |
// add custom guard provider
|
44 |
Auth::provider('mongo', function ($app, array $config) { |
45 |
return new MongoUserProvider($app->make('App\Models\Auth\User')); |
46 |
});
|
47 |
|
48 |
// add custom guard
|
49 |
Auth::extend('json', function ($app, $name, array $config) { |
50 |
return new JsonGuard(Auth::createUserProvider($config['provider']), $app->make('request')); |
51 |
});
|
52 |
}
|
53 |
|
54 |
public function register() |
55 |
{
|
56 |
$this->app->bind( |
57 |
'App\Services\Contracts\NosqlServiceInterface', |
58 |
'App\Database\MongoDatabase'
|
59 |
);
|
60 |
}
|
61 |
}
|
Passons en revue la méthode boot
qui contient la plupart des liaisons du fournisseur.
Pour commencer, nous allons créer des liaisons pour les éléments App\Database\MongoDatabase
et App\Models\Auth\User
.
1 |
$this->app->bind('App\Database\MongoDatabase', function ($app) { |
2 |
return new MongoDatabase(config('mongo.defaults.host'), config('mongo.defaults.port'), config('mongo.defaults.database')); |
3 |
});
|
4 |
|
5 |
$this->app->bind('App\Models\Auth\User', function ($app) { |
6 |
return new User($app->make('App\Database\MongoDatabase')); |
7 |
});
|
Cela fait un moment que nous parlons de fournisseur et de gardien, et il est temps de brancher notre garde personnalisée au système d'authentification Laravel.
Nous avons utilisé la méthode de fournisseur de Auth
Facade pour ajouter notre fournisseur d'authentification personnalisé sous la clé Mongo. Rappelez-vous que la clé reflète les paramètres ajoutés précédemment dans le fichier auth.php
.
1 |
Auth::provider('mongo', function ($app, array $config) { |
2 |
return new MongoUserProvider($app->make('App\Models\Auth\User')); |
3 |
});
|
De la même manière, nous allons injecter notre implémentation Guard personnalisée en utilisant la méthode extend de la façade Auth
.
1 |
Auth::extend('json', function ($app, $name, array $config) { |
2 |
return new JsonGuard(Auth::createUserProvider($config['provider']), $app->make('request')); |
3 |
});
|
Nous avons ensuite utilisé une méthode de registre
pour lier l'interface App\Services\Contracts\NosqlServiceInterface
à l'implémentation App\Database\MongoDatabase
.
1 |
$this->app->bind( |
2 |
'App\Services\Contracts\NosqlServiceInterface', |
3 |
'App\Database\MongoDatabase'
|
4 |
);
|
Ainsi, chaque fois qu'il est nécessaire de résoudre la dépendance App\Services\Contracts\NosqlServiceInterface
, Laravel répond en implémentant l'adaptateur App\Database\MongoDatabase
.
L'avantage d'utiliser cette approche est que l'on peut facilement échanger l'implémentation donnée avec une implémentation personnalisée. Par exemple, supposons que quelqu'un souhaite remplacer l'implémentation App\Database\MongoDatabase
par l'adaptateur CouchDB. Dans ce cas, il leur suffit d'ajouter la liaison correspondante dans la méthode register.
C'était donc le fournisseur de services à votre disposition. À l'heure actuelle, nous disposons de tout le nécessaire pour tester notre implémentation de protection personnalisée. La section suivante, qui porte sur la conclusion, traite de ce sujet.
Est-ce que ça marche?
Vous avez travaillé d'arrache-pied pour configurer votre première protection d'authentification personnalisée et il est maintenant temps de tirer parti des avantages qui s'offrent à vous et d'essayer.
Implémentons rapidement un fichier de contrôleur assez basique app/Http/Controllers/MongoController.php
comme indiqué ci-dessous.
1 |
<?php
|
2 |
// app/Http/Controllers/MongoController.php
|
3 |
namespace App\Http\Controllers; |
4 |
|
5 |
use App\Http\Controllers\Controller; |
6 |
use Illuminate\Contracts\Auth\Guard; |
7 |
|
8 |
class MongoController extends Controller |
9 |
{
|
10 |
public function login(Guard $auth_guard) |
11 |
{
|
12 |
if ($auth_guard->validate()) { |
13 |
// get the current authenticated user
|
14 |
$user = $auth_guard->user(); |
15 |
|
16 |
echo 'Success!'; |
17 |
} else { |
18 |
echo 'Not authorized to access this page!'; |
19 |
}
|
20 |
}
|
21 |
}
|
Examinez de près la dépendance de la méthode de connexion, qui nécessite l'implémentation de la protection Illuminate\Contracts\Auth\Guard
. Puisque nous avons défini la garde personnalisée comme garde par défaut dans le fichier auth.php
, c'est App\Services\Auth\JsonGuard
qui va être injecté!
Ensuite, nous avons appelé la méthode validate
de la classe App\Services\Auth\JsonGuard
, qui à son tour initie une série d'appels de méthode:
- Il appelle la méthode
retrieveByCredentials
de la classeApp\Extensions\MongoUserProvider
. - La méthode
retrieveByCredentials
appelle la méthodefetchUserByCredentials
de la classe UserApp\Models\Auth\User
. - La méthode
fetchUserByCredentials
appelle la méthodefind
deApp\Database\MongoDatabase
pour récupérer les informations d'identification de l'utilisateur. - Enfin, la méthode
find
deApp\Database\MongoDatabase
renvoie la réponse!
Si tout fonctionne comme prévu, nous devrions obtenir un utilisateur authentifié en appelant la méthode user
de notre gardien.
Pour accéder au contrôleur, vous devez ajouter une route associée dans le fichier routes/web.php
.
1 |
Route::get('/custom/mongo/login', 'MongoController@login'); |
Essayez d’accéder à l’URL http://votre-site-laravel/custom/mongo/login sans passer aucun paramètre et vous devriez voir un message "non autorisé".
D'autre part, essayez quelque chose comme http://votre-site-laravel/custom/mongo/login?Jsondata={"username": "admin", "password": "admin"} et qui devrait renvoyer un message de réussite. si l'utilisateur est présent dans votre base de données.
Veuillez noter qu'il ne s'agit que d'exemples illustrant le fonctionnement de la protection personnalisée. Vous devez implémenter une solution infaillible pour une fonctionnalité telle que la connexion. En fait, je viens de donner un aperçu du flux d'authentification; vous êtes responsable de la création d'une solution robuste et sécurisée pour votre application.
Cela met fin à notre voyage d’aujourd’hui et j'espère pouvoir revenir avec des informations plus utiles. Si vous souhaitez que j'écrive sur un sujet spécifique, n'oubliez pas de m'envoyer un message!
Conclusion
Le framework Laravel fournit un système d’authentification solide dans le noyau qui peut être étendu si vous souhaitez implémenter un système personnalisé. C'était le sujet de l'article d'aujourd'hui visant à implémenter une protection personnalisée et à la brancher au flux de travaux d'authentification Laravel.
Au cours de cette opération, nous avons mis au point un système qui authentifie l'utilisateur sur la base de la charge utile JSON de la demande et le met en correspondance avec la base de données MongoDB. Et pour y parvenir, nous avons créé une protection personnalisée et une implémentation de fournisseur personnalisée.
J'espère que l'exercice vous a fourni des informations sur le processus d'authentification de Laravel et que vous devriez maintenant vous sentir plus confiant quant à son fonctionnement interne.
Pour ceux d'entre vous qui débutent avec Laravel ou qui souhaitent développer leurs connaissances, leur site ou leur application avec des extensions, nous pouvons étudier de nombreuses choses sur le marché Envato.
J'aimerais entendre vos commentaires et suggestions, alors criez fort en utilisant le flux ci-dessous!