Cómo crear una guardia de autenticación personalizada en Laravel

En este artículo, vamos a cubrir el sistema de autenticación en el marco de Laravel. El objetivo principal de este artículo es crear una protección de autenticación personalizada mediante la ampliación del sistema de autenticación central..

Laravel proporciona un sistema de autenticación muy sólido en el núcleo que facilita la implementación de la autenticación básica. De hecho, solo necesita ejecutar un par de comandos artesanales para configurar los andamios de un sistema de autenticación.

Además, el sistema en sí está diseñado de tal manera que usted podría extenderlo y enchufar también sus adaptadores de autenticación personalizados. Eso es lo que discutiremos en detalle a lo largo de este artículo. Antes de continuar con la implementación de la protección de autenticación personalizada, comenzaremos con una discusión de los elementos básicos de los guardias y proveedores del sistema de autenticación Laravel..

Los elementos centrales: guardias y proveedores

El sistema de autenticación Laravel se compone de dos elementos en su núcleo: guardias y proveedores.

Guardias

Podría pensar en un guardia como una forma de suministrar 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 guarda de sesión mantiene el estado del usuario en cada solicitud mediante cookies y, por otro lado, el protector de token autentica al usuario al verificar un token válido en cada solicitud..

Entonces, como puede ver, el guardia define la lógica de la autenticación, y no es necesario que siempre se ocupe de eso mediante la recuperación de credenciales válidas del back-end. Puede implementar una protección que simplemente verifique la presencia de una cosa específica en los encabezados de solicitud y autentique a los usuarios basándose en eso.

Más adelante en este artículo, implementaremos una protección que verifica ciertos parámetros JSON en los encabezados de solicitud y recupera al usuario válido del back-end MongoDB.

Proveedores

Si el guardián define la lógica de autenticación, el proveedor de autenticación es responsable de recuperar al usuario del almacenamiento de back-end. Si el protector requiere que el usuario se valide en el almacenamiento de back-end, la implementación de la recuperación del usuario se realiza en el proveedor de autenticación..

Laravel se envía con dos proveedores de autenticación predeterminados: Base de datos y Elocuente. El proveedor de autenticación de la base de datos se ocupa de la recuperación directa de las credenciales de 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 de usuario del back end MongoDB..

Esa fue una introducción básica a los guardias y proveedores en el sistema de autenticación Laravel. A partir de la siguiente sección, nos centraremos en el desarrollo de la protección y el proveedor de autenticación personalizados.!

Un vistazo rápido a la configuración de archivos

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 protección personalizada..
  • config / mongo.php: Es el archivo que contiene la configuración de MongoDB..
  • app / Servicios / Contratos / NosqlServiceInterface.php: Es una interfaz que nuestra clase de base de datos Mongo personalizada implementa.
  • aplicación / base de datos / MongoDatabase.php: Es una clase de base de datos principal que interactúa con MongoDB.
  • aplicación / Modelos / Auth / User.php: Es la clase de modelo de usuario que implementa el contrato autentificable.
  • aplicación / Extensiones / MongoUserProvider.php: Es una implementación del proveedor de autenticación..
  • app / Servicios / Auth / JsonGuard.php: Es una implementación del controlador de protección de autenticación..
  • aplicación / Proveedores / 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 de demostración que implementaremos para probar nuestra protección personalizada.

No se preocupe si la lista de archivos no tiene mucho sentido, ya que analizaremos todo en detalle a medida que la revisamos..

Inmersión profunda en la implementación

En esta sección, pasaremos por la implementación de los archivos requeridos..

Lo primero que debemos hacer es informar a Laravel sobre nuestro guardia personalizado. Continúa y escribe los detalles de la guarda personalizada en el config / auth.php archivo como se muestra.

... 'guards' => ['web' => ['driver' => 'session', 'provider' => 'users',], 'api' => ['driver' => 'token', 'provider '=>' usuarios ',],' custom '=> [' driver '=>' json ',' provider '=>' mongo ',],], ... 

Como puede ver, hemos agregado nuestra protección personalizada bajo la personalizado llave.

A continuación, debemos agregar una entrada de proveedor asociado en el proveedores sección.

... 'suppliers' => ['users' => ['driver' => 'eloquent', 'model' => App \ User :: class,], 'mongo' => ['driver' => 'mongo' ], // 'users' => [// 'driver' => 'database', // 'table' => 'users', //],], ... 

Hemos añadido nuestra entrada de proveedor en el mongo llave.

Finalmente, cambiemos la protección de autenticación predeterminada de web a personalizada.

... 'defaults' => ['guard' => 'custom', 'passwords' => 'users',], ... 

Por supuesto, aún no funcionará, ya que aún no hemos implementado los archivos necesarios. Y eso es lo que discutiremos en las próximas secciones..

Configurar el controlador MongoDB

En esta sección, implementaremos los archivos necesarios que se refieren a la instancia de MongoDB subyacente.

Primero creamos un archivo de configuración config / mongo.php que contiene la configuración de conexión predeterminada de MongoDB.

 ['host' => 'HOST_IP', 'port' => 'HOST_PORT', 'database' => 'DB_NAME']];

Por supuesto, necesita cambiar los valores de los marcadores de posición según su configuración.

En lugar de crear directamente una clase que interactúe con MongoDB, crearemos una interfaz en primer lugar.

La ventaja de crear una interfaz es que proporciona un contrato que un desarrollador debe cumplir mientras lo implementa. Además, nuestra implementación de MongoDB podría intercambiarse fácilmente con otra implementación NoSQL si fuera necesario..

Sigue adelante y crea un archivo de interfaz app / Servicios / Contratos / NosqlServiceInterface.php con los siguientes contenidos.

Es una interfaz bastante simple que declara los métodos básicos de CRUD que debe definir una clase que implementa esta interfaz.

Ahora, vamos a definir una clase real en aplicación / base de datos / MongoDatabase.php.

connection = new MongoClient ("mongodb: // $ host: $ port"); $ this-> database = $ this-> connection -> $ database;  / ** * @see \ App \ Services \ Contracts \ NosqlServiceInterface :: find () * / public function find ($ collection, Array $ criteria) return $ this-> database -> $ collection -> findOne ( $ criterios);  public function create ($ collection, Array $ document)  public function update ($ collection, $ id, Array $ document)  public function delete ($ collection, $ id) 

Por supuesto, asumo que has instalado MongoDB y la extensión PHP de MongoDB correspondiente.

los __construir método crea una instancia de la MongoClient Clase con los parámetros necesarios. El otro método importante que nos interesa es el encontrar Método, que recupera el registro en función de los criterios proporcionados como argumentos del método..

Así que esa fue la implementación del controlador MongoDB, y traté de hacerlo lo más simple posible..

Configurar el modelo de usuario

Cumpliendo con los estándares del sistema de autenticación, necesitamos implementar el modelo de Usuario que debe implementar el Illuminate \ Contracts \ Auth \ Authenticatable contrato.

Sigue adelante y crea un archivo. aplicación / Modelos / Auth / User.php con los siguientes contenidos.

conn = $ conn;  / ** * Recuperar usuario por credenciales * * @param array $ credentials * @return Illuminate \ Contracts \ Auth \ Authenticatable * / public function fetchUserByCredentials (Array $ credentials) $ arr_user = $ this-> conn-> find (' usuarios ', [' nombre de usuario '=> $ credenciales [' nombre de usuario ']]); if (! is_null ($ arr_user)) $ this-> username = $ arr_user ['username']; $ this-> password = $ arr_user ['password'];  devuelve $ esto;  / ** * @inheritDoc * @see \ Illuminate \ Contracts \ Auth \ Authenticatable :: getAuthIdentifierName () * / public function getAuthIdentifierName () return "username";  / ** * @inheritDoc * @see \ Illuminate \ Contracts \ Auth \ Authenticatable :: getAuthIdentifier () * / public function getAuthIdentifier () return $ this -> $ this-> getAuthIdentifierName ());  / ** * @inheritDoc * @see \ Illuminate \ Contracts \ Auth \ Authenticatable :: getAuthPassword () * / public function getAuthPassword () return $ this-> password;  / ** * @inheritDoc * @see \ Illuminate \ Contracts \ Auth \ Authenticatable :: getRememberToken () * / public function getRememberToken () if (! empty ($ this-> getRememberTokenName ())) return $ este -> $ this-> getRememberTokenName ();  / ** * @inheritDoc * @see \ Illuminate \ Contracts \ Auth \ Authenticatable :: setRememberToken () * / public function setRememberToken ($ value) if (! empty ($ this-> getRememberTokenName ())) $ this -> $ this-> getRememberTokenName () = $ value;  / ** * @inheritDoc * @see \ Illuminate \ Contracts \ Auth \ Authenticatable :: getRememberTokenName () * / public function getRememberTokenName () return $ this-> rememberTokenName; 

Ya deberías haber notado que App \ Models \ Auth \ User implementa el Illuminate \ Contracts \ Auth \ Authenticatable contrato.

La mayoría de los métodos implementados en nuestra clase son autoexplicativos. Dicho esto, hemos definido la fetchUserByCredentials Método, que recupera al usuario del back-end disponible. En nuestro caso, será un MongoDatabase Clase 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 vimos anteriormente, el sistema de autenticación Laravel consta de dos elementos: guardias y proveedores.

En esta sección, crearemos un proveedor de autenticación que se ocupa de la recuperación del usuario desde el back-end.

Sigue adelante y crea un archivo. aplicación / Extensiones / MongoUserProvider.php Como se muestra abajo.

model = $ userModel;  / ** * Recuperar un usuario por las credenciales dadas. * * @param array $ credentials * @return \ Illuminate \ Contracts \ Auth \ Authenticatable | null * / public function retrieveByCredentials (array $ credentials) if (vacío ($ credentials)) return;  $ user = $ this-> model-> fetchUserByCredentials (['username' => $ credentials ['username']]); devuelve $ usuario;  / ** * Validar un usuario con las credenciales dadas. * * @param \ Illuminate \ Contracts \ Auth \ Authenticatable $ user * @param array $ credentials Solicitar credenciales * @return bool * / public function validateCredentials (Usuario autenticable $, Array $ credentials) return ($ credentials ['username'] == $ usuario-> getAuthIdentifier () && md5 ($ credenciales ['contraseña']) == $ usuario-> getAuthPassword ());  función pública retrieveById ($ identificador)  función pública retrieveByToken ($ identificador, $ token)  función pública updateRememberToken ($ autenticable $ usuario, $ token) 

Nuevamente, debe asegurarse de que el proveedor personalizado debe implementar el Illuminate \ Contracts \ Auth \ UserProvider contrato.

Avanzando, define dos métodos importantes: retrieveByCredentials y validateCredentials.

los retrieveByCredentials Este método se utiliza para recuperar las credenciales de usuario utilizando la clase de modelo de usuario que se trató en la sección anterior. Por otro lado, la validateCredentials El método se utiliza para validar un usuario contra el conjunto de credenciales dado.

Y esa fue la implementación de nuestro proveedor de autenticación personalizado. En la siguiente sección, continuaremos y crearemos un protector que interactúe con el Proveedor de MongoUser proveedor de autenticación.

Configurar la Guardia de Autentificación

Como vimos anteriormente, la protección en el sistema de autenticación Laravel estipula cómo se autentica el usuario. En nuestro caso, comprobaremos la presencia del jsondata parámetro de solicitud que debe contener la cadena codificada en JSON de las credenciales.

En esta sección, crearemos un protector que interactúa con el proveedor de autenticación que se acaba de crear en la última sección..

Sigue adelante y crea un archivo. app / Servicios / Auth / JsonGuard.php con los siguientes contenidos.

solicitud = $ solicitud; $ this-> provider = $ provider; $ this-> user = NULL;  / ** * Determine si el usuario actual está autenticado. * * @return bool * / public function check () return! is_null ($ this-> user ());  / ** * Determine si el usuario actual es un invitado. * * @return bool * / public function guest () return! $ esto-> cheque ();  / ** * Obtener el usuario autenticado actualmente. * * @return \ Illuminate \ Contracts \ Auth \ Authenticatable | null * / public function user () si (! is_null ($ this-> user)) return $ this-> user;  / ** * Obtenga los parámetros JSON de la solicitud actual * * @return string * / public function getJsonParams () $ jsondata = $ this-> request-> query ('jsondata'); return (! empty ($ jsondata)? json_decode ($ jsondata, TRUE): NULL);  / ** * Obtener el ID del usuario autenticado actualmente. * * @return string | null * / public function id () if ($ user = $ this-> user ()) return $ this-> user () -> getAuthIdentifier ();  / ** * Validar las credenciales de un usuario. * * @return bool * / public function validate (Array $ credentials = []) if (empty ($ credentials ['username']) || empty ($ credentials ['password'])) if (! $ credentials = $ this-> getJsonParams ()) return false;  $ user = $ this-> provider-> retrieveByCredentials ($ credentials); if (! is_null ($ user) && $ this-> provider-> validateCredentials ($ user, $ credentials)) $ this-> setUser ($ user); devuelve verdadero  else devolver falso;  / ** * Establecer el usuario actual. * * @param Array $ usuario Información del usuario * @return void * / public function setUser (Usuario $ autenticable) $ this-> user = $ usuario; devuelve $ esto; 

En primer lugar, nuestra clase necesita implementar el Iluminar \ Contratos \ Auth \ Guard interfaz. Por lo tanto, necesitamos definir todos los métodos declarados en esa interfaz..

Lo importante a tener en cuenta aquí es que la __construir función requiere una implementación de Illuminate \ Contracts \ Auth \ UserProvider. En nuestro caso, vamos a pasar 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 de usuario del parámetro de solicitud denominado jsondata. Como se espera que recibamos una cadena codificada en JSON de las credenciales de usuario, hemos utilizado el json_decode Función para decodificar los datos JSON.

En la función de validación, lo primero que comprobamos es la existencia de la $ credenciales argumento. Si no está presente, llamaremos al getJsonParams Método para recuperar las credenciales de usuario de los parámetros de solicitud.

A continuación, llamamos a la retrieveByCredentials método de la Proveedor de MongoUser Proveedor que recupera al usuario del back-end de la base de datos MongoDB. Finalmente, es el validateCredentials método de la Proveedor de MongoUser Proveedor que verifica la validez del Usuario..

Así que esa fue 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.

Poniendolo todo junto

Hasta ahora, hemos desarrollado todos los elementos de la protección de autenticación personalizada que deberían proporcionarnos un nuevo sistema de autenticación. Sin embargo, no funcionará de manera inmediata, ya que necesitamos registrarlo en primer lugar mediante el uso de los enlaces de contenedores del servicio Laravel.

Como ya debe saber, el proveedor de servicios Laravel es el lugar adecuado para implementar los enlaces necesarios.

Adelante, abre el archivo. aplicación / Proveedores / AuthServiceProvider.php Eso nos permite agregar enlaces de contenedor de servicio de autenticación. Si no contiene ningún cambio personalizado, simplemente puede reemplazarlo con el siguiente contenido.

 'App \ Policies \ ModelPolicy',]; / ** * Registrar cualquier servicio de autenticación / autorización. * * @return void * / public function boot () $ this-> registerPolicies (); $ this-> app-> bind ('App \ Database \ MongoDatabase', function ($ app) return new MongoDatabase (config ('mongo.defaults.host'), config ('mongo.defaults.port'), config ('mongo.defaults.database'));); $ this-> app-> bind ('App \ Models \ Auth \ User', function ($ app) return nuevo Usuario ($ app-> make ('App \ Database \ MongoDatabase'));); // agregar el proveedor de protección personalizado Auth :: provider ('mongo', function ($ app, array $ config) return nuevo MongoUserProvider ($ app-> make ('App \ Models \ Auth \ User'));); // agregar guard personalizado custom Auth :: extend ('json', function ($ app, $ name, array $ config) return new JsonGuard (Auth :: createUserProvider ($ config ['provider']), $ app-> make ('solicitud')); );  registro de función pública () $ this-> app-> bind ('App \ Services \ Contracts \ NosqlServiceInterface', 'App \ Database \ MongoDatabase'); 

Vayamos a través de la bota Método que contiene la mayoría de los enlaces de proveedores..

Para empezar, crearemos enlaces para el App \ Database \ MongoDatabase y App \ Models \ Auth \ User elementos.

$ this-> app-> bind ('App \ Database \ MongoDatabase', function ($ app) return new MongoDatabase (config ('mongo.defaults.host'), config ('mongo.defaults.port'), config ('mongo.defaults.database'));); $ this-> app-> bind ('App \ Models \ Auth \ User', function ($ app) return nuevo Usuario ($ app-> make ('App \ Database \ MongoDatabase')););

Hace un tiempo que hemos estado hablando de proveedor y guardia, y es hora de conectar nuestra guardia personalizada al sistema de autenticación Laravel.

Hemos utilizado el método del proveedor de Autenticación Fachada para agregar nuestro proveedor de autenticación personalizado bajo la clave mongo. Recuerde que la clave refleja la configuración que se agregó anteriormente en el auth.php expediente.

Auth :: provider ('mongo', function ($ app, array $ config) return new MongoUserProvider ($ app-> make ('App \ Models \ Auth \ User')););

De manera similar, inyectaremos nuestra implementación de protección personalizada utilizando el método extendido de Autenticación fachada.

Auth :: extend ('json', función ($ app, $ name, array $ config) devolver el nuevo JsonGuard (Auth :: createUserProvider ($ config ['provider']), $ app-> make ('request') ););

A continuación, hay una registro Método que hemos utilizado para enlazar el Aplicación \ Servicios \ Contratos \ NosqlServiceInterface interfaz a la App \ Database \ MongoDatabase implementación.

$ this-> app-> bind ('App \ Services \ Contracts \ NosqlServiceInterface', 'App \ Database \ MongoDatabase');

Así que cada vez que hay una necesidad de resolver el Aplicación \ Servicios \ Contratos \ NosqlServiceInterface dependencia, Laravel responde con la implementación del App \ Database \ MongoDatabase adaptador.

La ventaja de utilizar este enfoque es que uno podría intercambiar fácilmente la implementación dada con una implementación personalizada. Por ejemplo, digamos que alguien quisiera reemplazar el App \ Database \ MongoDatabase Implementación con el adaptador CouchDB en el futuro. En ese caso, solo necesitan agregar el enlace correspondiente en el método de registro..

Así que ese era el proveedor de servicios a su disposición. En este momento, tenemos todo lo que se requiere para probar nuestra implementación de protección personalizada, por lo que la siguiente y última sección es todo sobre eso.

Funciona?

Ha hecho todo el trabajo duro para configurar su primera protección de autenticación personalizada, y ahora es el momento de cosechar los beneficios a medida que avanzamos y lo probamos.

Vamos a implementar rápidamente un archivo controlador bastante básico app / Http / Controllers / MongoController.php Como se muestra abajo.

validate ()) // obtener el usuario autenticado actual $ user = $ auth_guard-> user (); echo '¡Éxito!';  else echo '¡No autorizado para acceder a esta página!'; 

Observe detenidamente la dependencia del método de inicio de sesión, que requiere la implementación de Iluminar \ Contratos \ Auth \ Guard Guardia. Desde que hemos establecido el personalizado guardia como el guardia por defecto en el auth.php archivo, es el App \ Servicios \ Auth \ JsonGuard Eso será inyectado en realidad!

A continuación, hemos llamado a la validar método de la App \ Servicios \ Auth \ JsonGuard clase, que a su vez inicia una serie de llamadas de método:

  • Llama a la retrieveByCredentials método de la App \ Extensions \ MongoUserProvider clase.
  • los retrieveByCredentials método llama al fetchUserByCredentials método del usuario App \ Models \ Auth \ User clase.
  • los fetchUserByCredentials método llama al encontrar método de la App \ Database \ MongoDatabase para recuperar las credenciales de usuario.
  • Finalmente, el encontrar método de la App \ Database \ MongoDatabase devuelve la respuesta!

Si todo funciona como se espera, deberíamos obtener un usuario autenticado llamando al usuario método de nuestra guardia.

Para acceder al controlador, debe agregar una ruta asociada en el rutas / web.php expediente.

Route :: get ('/ custom / mongo / login', 'MongoController @ login');

Intente acceder a la URL http: // su-laravel-site / custom / mongo / login sin pasar ningún parámetro y debería ver un mensaje "no autorizado".

Por otro lado, intente algo como http: // your-laravel-site / custom / mongo / login? Jsondata = "username": "admin", "password": "admin" y eso debería devolver un mensaje de éxito Si el usuario está presente en su base de datos..

Tenga en cuenta que esto es solo a modo de ejemplo, para demostrar cómo funciona la protección personalizada. Debe implementar una solución infalible para una función como el inicio de sesión. De hecho, acabo de proporcionar una visión del flujo de autenticación; Usted es responsable de crear una solución robusta y segura para su aplicación..

Eso termina nuestro viaje de hoy, y espero volver con más cosas útiles. Si quieres que escriba sobre algún tema específico, no olvides escribirme una línea.!

Conclusión

El marco Laravel proporciona un sistema de autenticación sólido en el núcleo que podría extenderse si desea implementar uno personalizado. Ese fue el tema del artículo de hoy para implementar una protección personalizada y conectarlo al flujo de trabajo de autenticación Laravel..

En el transcurso de eso, seguimos adelante y desarrollamos un sistema que autentica al usuario según la carga útil de JSON en la solicitud y lo combina con la base de datos de MongoDB. Y para lograrlo, terminamos creando una protección personalizada y una implementación de proveedor personalizada..

Espero que el ejercicio le haya brindado una idea del flujo de autenticación de Laravel, y ahora debería sentirse más seguro con respecto a su funcionamiento interno..

Para aquellos de ustedes que ya están comenzando con Laravel o que desean ampliar sus conocimientos, sitio o aplicación con extensiones, tenemos una variedad de cosas que puede estudiar en Envato Market.

Me encantaría escuchar tus comentarios y sugerencias, así que grita en voz alta usando la siguiente información!