() translation by (you can also view the original English article)
En este artículo, vamos a cubrir el sistema de autenticación en el Framework de Laravel. El objetivo principal de este artículo es crear una protección de autenticación personalizada extendiendo el sistema de autenticación central.
Laravel proporciona un sistema de autenticación muy sólido en el núcleo que hace que la implementación de la autenticación básica sea muy sencilla. De hecho, solo necesitas ejecutar un par de comandos artisan para configurar el scaffolding de un sistema de autenticación.
Además, el sistema en sí está diseñado de tal manera que podrías ampliarlo y conectar tus adaptadores de autenticación personalizados también. Eso es lo que discutiremos en detalle a lo largo de este artículo. Antes de seguir adelante y profundizar en la implementación de la protección de autenticación personalizada, comenzaremos con una discusión sobre los elementos básicos en el sistema de autenticación de Laravel: guardias y proveedores.
Los elementos principales: guardias y proveedores
El sistema de autenticación de Laravel se compone de dos elementos principales —guardias y proveedores.
Guardias
Podrías pensar en un guardia como una forma de proporcionar la lógica que se utiliza para identificar a los usuarios autenticados. En el núcleo, Laravel proporciona diferentes guardias como sesión y token. El guardia de sesión mantiene el estado del usuario en cada solicitud mediante cookies y, por otro lado, el guardián del token autentica al usuario marcando un token válido en cada solicitud.
Entonces, como puedes ver, el guardia define la lógica de la autenticación, y no es necesario que siempre trate con eso recuperando credenciales válidas desde el back-end. Puedes implementar un guardia que simplemente verifique la presencia de algo específico en los encabezados de solicitud y autentique a los usuarios en función de eso.
Más adelante en este artículo, implementaremos un guardia que verifique ciertos parámetros JSON en los encabezados de solicitud y recupere al usuario válido del back-end de MongoDB.
Proveedores
Si el guardia define la lógica de autenticación, el proveedor de autenticación es responsable de recuperar al usuario del almacenamiento de fondo. Si el guardia requiere que el usuario deba ser validado contra el almacenamiento de back-end, la implementación de recuperación del usuario entra en el proveedor de autenticación.
Laravel se envía con dos proveedores de autenticación predeterminados: base de datos y Eloquent. El proveedor de autenticación de la base de datos se ocupa de la recuperación directa de las credenciales del usuario del almacenamiento de back-end, mientras que Eloquent proporciona una capa de abstracción que hace lo necesario.
En nuestro ejemplo, implementaremos un proveedor de autenticación MongoDB que obtenga las credenciales del usuario desde el back-end de MongoDB.
Entonces esa fue una introducción básica a los guardias y proveedores en el sistema de autenticación de Laravel. A partir de la próxima sección, nos centraremos en el desarrollo del proveedor y protector de autenticación personalizado.
Un vistazo rápido a la configuración del archivo
Echemos un vistazo rápido a la lista de archivos que implementaremos a lo largo de este artículo.
-
config/auth.php:
Es el archivo de configuración de autenticación en el que agregaremos una entrada de nuestra guardia personalizada. -
config/mongo.php
: es el archivo que contiene la configuración de MongoDB. -
app/Services/Contracts/NosqlServiceInterface.php
: Es una interfaz que implementa nuestra clase personalizada de base de datos MongoDB. -
app/Database/MongoDatabase.php
: es una clase de base de datos principal que interactúa con MongoDB. -
app/Models/Auth/User.php
: es la clase de modelo de usuario que implementa la declaración Autenticable. -
app/Extensions/MongoUserProvider.php:
es una implementación del proveedor de autenticación. -
app/Services/Auth/JsonGuard.php
: es una implementación del controlador de protección de autenticación. -
app/Providers/AuthServiceProvider.php:
este es un archivo existente que usaremos para agregar nuestros enlaces de contenedor de servicio. -
app/Http/Controllers/MongoController.php
: es un archivo de controlador demo que implementaremos para probar nuestra guardia personalizada.
No te preocupes si la lista de los archivos no tiene mucho sentido aún, ya que discutiremos todo en detalle a medida que avancemos.
Inmersión profunda en la implementación
En esta sección, revisaremos la implementación de los archivos requeridos.
Lo primero que debemos hacer es informar a Laravel sobre nuestra guardia personalizada. Continúa e ingresa los detalles del protector personalizado en el archivo config/auth.php
como se muestra.
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 |
...
|
Como puedes ver, hemos agregado nuestro protector personalizado bajo la clave personalizada.
A continuación, debemos agregar una entrada de proveedor asociada en la sección de proveedores.
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 |
...
|
Hemos agregado nuestra entrada de proveedor bajo la clave mongo.
Finalmente, cambiemos el protector de autenticación predeterminado de web a personalizado.
1 |
...
|
2 |
...
|
3 |
'defaults' => [ |
4 |
'guard' => 'custom', |
5 |
'passwords' => 'users', |
6 |
],
|
7 |
...
|
8 |
...
|
Por supuesto, no funcionará aún, ya que aún no hemos implementado los archivos necesarios. Y eso es lo que discutiremos en las próximas secciones.
Configura el controlador MongoDB
En esta sección, implementaremos los archivos necesarios que hablan con la instancia de MongoDB subyacente.
Primero crearemos un archivo de configuración config/mongo.php
que contenga la configuración de conexión de MongoDB por defecto.
1 |
<?php
|
2 |
return [ |
3 |
'defaults' => [ |
4 |
'host' => '{HOST_IP}', |
5 |
'port' => '{HOST_PORT}', |
6 |
'database' => '{DB_NAME}' |
7 |
]
|
8 |
];
|
Por supuesto, debes cambiar los valores del marcador de posición según tu configuración.
En lugar de crear directamente una clase que interactúe con MongoDB, crearemos una interfaz en primer lugar.
El beneficio de crear una interfaz es que proporciona una declaración que un desarrollador debe cumplir al implementarlo. Además, nuestra implementación de MongoDB podría intercambiarse fácilmente con otra implementación de NoSQL si fuese necesario.
Continúa y crea una aplicación de archivo de interfaz app/Services/Contracts/NosqlServiceInterface.php
con los siguientes contenidos.
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 |
}
|
Es una interfaz bastante simple que declara los métodos CRUD básicos que una clase debe definir y que implementa esta interfaz.
Ahora, definamos una clase real en 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 |
}
|
Por supuesto, supongo que has instalado MongoDB y la extensión de MongoDB PHP correspondiente.
El método __construct
instancia la clase MongoClient
con los parámetros necesarios. El otro método importante que nos interesa es el método de búsqueda find
, el cual recupera el registro según los criterios proporcionados como argumentos de método.
Así que esa fue la implementación del controlador MongoDB, y traté de mantenerlo lo más simple posible.
Configurar el modelo de usuario
Siguiendo los estándares del sistema de autenticación, debemos implementar el modelo de usuario que debe implementar la declaración Illuminate\Contracts\Auth\Authenticatable
.
Continúa y crea un archivo en app/Models/Auth/User.php
con los siguientes contenidos.
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 |
}
|
Ya deberías haber notado que App\Models\Auth\User
implementa la declaración Illuminate\Contracts\Auth\Authenticatable
.
La mayoría de los métodos implementados en nuestra clase son autoexplicativos. Habiendo dicho eso, hemos definido el método fetchUserByCredentials
, el cual recupera al usuario mediante el back end disponible. En nuestro caso, será una clase MongoDatabase
a la que se llamará para recuperar la información necesaria.
Así que esa es la implementación del modelo de Usuario.
Configurar el proveedor de autenticación
Como mencionamos anteriormente, el sistema de autenticación de Laravel consta de dos elementos: guardias y proveedores.
En esta sección, crearemos un proveedor de autenticación que se ocupará de la recuperación del usuario desde el back-end.
Continúa y crea un archivo en app/Extensions/MongoUserProvider.php
como se muestra a continuación.
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 |
}
|
De nuevo, debes asegurarte de que el proveedor personalizado debe implementar la declaración Illuminate\Contracts\Auth\UserProvider
.
Para seguir avanzando, define dos métodos importantes: retrieveByCredentials y validateCredentials.
El método retrieveByCredentials
se usa para recuperar las credenciales de usuario utilizando la clase de modelo del usuario, el cual se discutió en la sección anterior. Por otro lado, el método validateCredentials
se usa para validar a un usuario contra un conjunto dado de credenciales.
Y esa fue la implementación de nuestro proveedor de autenticación personalizado. En la siguiente sección, procederemos a crear un guardia que interactúe con el proveedor de autenticación MongoUserProvider
.
Configurar la Guardia de autenticación
Como mencionamos anteriormente, el guardia del sistema de autenticación de Laravel indica cómo se autentica al usuario. En nuestro caso, verificaremos la presencia del parámetro de solicitud jsondata que debe contener la cadena de credenciales codificada en JSON.
En esta sección, crearemos un guardia que interactúa con el proveedor de autenticación que se acaba de crear en la última sección.
Ahora vamos a crear un archivo en app/Services/Auth/JsonGuard.php
con los siguientes contenidos.
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 |
}
|
En primer lugar, nuestra clase necesita implementar la interfaz Illuminate\Contracts\Auth\Guard
. Por lo tanto, necesitamos definir todos los métodos declarados en esa interfaz.
Lo importante a tener en cuenta aquí es que la función __construct
requiere una implementación de Illuminate\Contracts\Auth\UserProvider
. En nuestro caso, pasaremos una instancia de App\Extensions\MongoUserProvider
, como veremos en la sección posterior.
A continuación, hay una función getJsonParams
que recupera las credenciales del usuario del parámetro de solicitud llamado jsondata
. Como se espera que recibamos una cadena codificada JSON de las credenciales del usuario, hemos utilizado la función json_decode
para decodificar los datos JSON.
En la función de validación, lo primero que verificamos es la existencia del argumento $credentials
. Si no está presente, llamaremos al método getJsonParams
para recuperar las credenciales del usuario de los parámetros de solicitud.
Ahora, vamos a llamar al método retrieveByCredentials
del proveedor MongoUserProvider
que recupera al usuario de la base de datos de MongoDB. Finalmente, es el método validateCredentials
del proveedor MongoUserProvider
el que verifica la validez del usuario.
Aquí termina la implementación de nuestra guardia personalizada. La siguiente sección describe cómo unir estas piezas para formar un sistema de autenticación exitoso.
Juntando todo
Hasta ahora, hemos desarrollado todos los elementos del protector de autenticación personalizado. Este debería proporcionarnos un nuevo sistema de autenticación. Sin embargo, no funcionará fuera de la caja ya que en primer lugar, necesitamos registrarlo utilizando los enlaces de contenedor de servicio Laravel.
Como ya debes saber, el proveedor de servicios Laravel es el lugar adecuado para implementar los enlaces necesarios.
Continúa y abre el archivo app/Providers/AuthServiceProvider.php
el cual nos permite agregar enlaces de contenedor de servicio de autenticación. Si no contiene ningún cambio personalizado, puedes reemplazarlo con los siguientes contenidos.
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 |
}
|
Veamos el método de arranque boot
que contiene la mayoría de los enlaces de proveedor.
Para empezar, crearemos enlaces para los elementos App\Database\MongoDatabase
y 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 |
});
|
Ha pasado un tiempo en el cual hemos estado hablando de proveedores y guardias, y es hora de conectar nuestro guardia personalizado en el sistema de autenticación Laravel.
Hemos utilizado el método de proveedor de Auth Facade
para agregar nuestro proveedor de autenticación personalizado bajo la clave mongo. Recuerda que la clave refleja la configuración que se agregó anteriormente en el archivo auth.php
.
1 |
Auth::provider('mongo', function ($app, array $config) { |
2 |
return new MongoUserProvider($app->make('App\Models\Auth\User')); |
3 |
});
|
De manera similar, inyectaremos nuestra implementación de guardia personalizada utilizando el método extendido de la Auth facade
.
1 |
Auth::extend('json', function ($app, $name, array $config) { |
2 |
return new JsonGuard(Auth::createUserProvider($config['provider']), $app->make('request')); |
3 |
});
|
A continuación, hay un método de registro llamado register
que hemos utilizado para vincular App\Services\Contracts\NosqlServiceInterface
con la implementación de App\Database\MongoDatabase
.
1 |
$this->app->bind( |
2 |
'App\Services\Contracts\NosqlServiceInterface', |
3 |
'App\Database\MongoDatabase'
|
4 |
);
|
Por lo tanto, siempre que sea necesario resolver la dependencia App\Services\Contracts\NosqlServiceInterface
, Laravel responde con la implementación del adaptador App\Database\MongoDatabase
.
El beneficio de usar esta propuesta es que uno puede cambiar fácilmente la implementación dada con una implementación personalizada. Por ejemplo, digamos que a alguien le gustaría reemplazar la implementación App\Database\MongoDatabase
con el adaptador CouchDB en el futuro. En ese caso, solo necesitaría agregar el enlace correspondiente en el método de registro.
Por lo tanto, ese era el proveedor de servicios a tu disposición. En este momento, tenemos todo lo que se requiere para probar nuestra implementación de guardia personalizada, por lo que la siguiente y última sección se trata de eso.
¿Funciona?
Has hecho todo el trabajo de configuración de tu primer protector de autenticación personalizado, y ahora es el momento de cosechar los beneficios, ya que vamos a continuar y lo probaremos.
Implementemos rápidamente un controlador bastante básico app/Http/Controllers/MongoController.php
como se muestra a continuación.
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 |
}
|
Observa de cerca la dependencia del método de inicio de sesión, que requiere la implementación de la protección Illuminate\Contracts\Auth\Guard
. Como hemos configurado el protector personalizado como el protector predeterminado en el archivo auth.php
, es App\Services\Auth\JsonGuard
que se inyectará en realidad.
A continuación, llamamos al método de validación llamado validate
de la clase App\Services\Auth\JsonGuard
, que a su vez inicia una serie de llamadas a métodos:
- Llama al método
retrieveByCredentials
de la claseApp\Extensions\MongoUserProvider
. - El método
retrieveByCredentials
llama al métodofetchUserByCredentials
de la clase UserApp\Models\Auth\User
. - El método
fetchUserByCredentials
llama al método de búsquedafind
deApp\Database\MongoDatabase
para recuperar las credenciales del usuario. - Finalmente, el método
find
deApp\Database\MongoDatabase
devuelve la respuesta.
Si todo funciona como se espera, deberíamos obtener un usuario autenticado llamando al método user
de nuestra guardia.
Para acceder al controlador, debes agregar una ruta asociada en el archivo routes/web.php
.
1 |
Route::get('/custom/mongo/login', 'MongoController@login'); |
Intenta acceder a la URL http://tu-sitio-laravel/custom/mongo/login sin pasar ningún parámetro y deberías ver un mensaje de "no autorizado".
Por otro lado, prueba algo como http://tu-sitio-laravel/custom/mongo/login?jsondata={"username":"admin","password":"admin"} y eso debería devolver un mensaje de éxito si el usuario está presente en tu base de datos.
Ten en cuenta que esto es solo para fines de ejemplo, para demostrar cómo funciona el protector personalizado. Deberías implementar una solución infalible para una característica como el inicio de sesión. De hecho, acabo de proporcionar una idea del flujo de autenticación; eres responsable de construir una solución robusta y segura para tu aplicación.
Aquí finaliza nuestro viaje de hoy, y con suerte volveré con más cosas útiles. Si quieres que escriba sobre algún tema específico, ¡no olvides dejarme una línea!
Conclusión
El framework de Laravel proporciona un sistema de autenticación sólido en el núcleo que podría ampliarse si deseas implementar uno personalizado. Ese fue el tema del artículo de hoy para implementar un guardia personalizado y conectarlo al flujo de trabajo de autenticación de Laravel.
En el transcurso de eso, continuamos y desarrollamos un sistema que autentica al usuario basado en la carga JSON en la solicitud y lo combina con la base de datos MongoDB. Y para lograr eso, terminamos creando un protector personalizado y una implementación de proveedor personalizado.
Espero que el ejercicio te haya proporcionado una idea del flujo de autenticación de Laravel, y ahora deberías sentirte más seguro acerca de su funcionamiento interno.
Para aquellos de ustedes que recién están comenzando con Laravel o buscando ampliar el conocimiento, sitio o aplicación con extensiones, tenemos una variedad de cosas que pueden estudiar en Envato Market.
Me encantaría escuchar tus comentarios y sugerencias, ¡así que grita en voz alta usando el feed a continuación!.