Authentication
Authentication
En esta documentación se detallan las formas en las que se pueden crear las diferentes rutas de registro y login. No confundir con paquetes como Sanctum que lo que hace es proteger a un grupo de rutas de peticiones no autenticadas.
Introducción
Muchas aplicaciones proveen una forma para que sus usuarios puedan autenticarse en la aplicación y hacer login. Implementar esta funcionalidad en las aplicaciones web puede ser complejo y potencialmente arriesgado. Por esta razón, laravel te da las herramientas que necesitas para implementar la autenticación de forma rápida, segura y fácil.
En su core, la autenticación de laravel está formado por “guards” y “providers”.
Las “Guards” definen como los usuarios son autenticados por cada request. Por ejemplo, Laravel trae una session guard la cual mantiene el estado usando el almacenado en sesión y enviando la sesión en la respuesta a través de cookies.
Los proveedores definen como los usuarios son devueltos desde el almacenamiento persistente. Laravel trae soporte para devolver usuarios usando Eloquent y el query builder.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'customers',
],
],
// provider hace referencia al array mas abajo, que indica como se va a
// recuperar un usuario de la base de datos.
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'users' => [
'driver' => 'database',
'table' => 'users',
],
],
// En el primero se utiliza el modelo de eloquent para obtener los datos,
// en el segundo se utiliza el query builder.
Tu archivo de configuración de autenticación se encuentra en config/auth.php. Este archivo contiene diferentes opciones para retocar el comportamiento del servicio de autenticación de Laravel. Es posible crear guards personalizados y drivers personalizados.
Starter Kits
Para empezar rápido puedes instalar un kit inicial de Laravel. Incluso si decides no utilizar un kit inicial en tu aplicación Laravel final, instalar el kit inicial Laravel Breeze puede ser una excelente oportunidad para aprender cómo implementar toda la funcionalidad de autenticación de Laravel en un proyecto real de Laravel. Dado que Laravel Breeze crea controladores, rutas y vistas de autenticación por ti, puedes examinar el código dentro de estos archivos para aprender cómo se implementan las características de autenticación de Laravel.
Database Considerations
- Es necesario que el campo password del modelo de users, tenga una longitud de al menos 60 caracteres.
- La tabla user tienen que contener un campo de tipo nullable y de tipo string, remember_token de al menos 100 caracteres. Esta columna será usada para guardar un token para los usuarios que seleccionen la opción de “remember me” cuando se logeen en tu aplicación.
Ecosystem Overview
Primero, vamos a considerar cómo funciona la autenticación. Cuando se usa un navegador web, un usuario proporcionará su nombre de usuario y contraseña a través de un formulario de inicio de sesión. Si estas credenciales son correctas, la aplicación almacenará información sobre el usuario autenticado en la sesión del usuario. Una cookie emitida al navegador contiene el ID de sesión para que las solicitudes posteriores puedan asociar al usuario con la sesión correcta. Después de recibir la cookie de sesión, la aplicación recuperará los datos de la sesión en función del ID de sesión, notará que la información de autenticación se ha almacenado en la sesión y considerará al usuario como “autenticado”.
Cuando un servicio remoto necesita autenticarse para acceder a una API, las cookies no se utilizan típicamente para la autenticación porque no hay un navegador web. En su lugar, el servicio remoto envía un token a la API en cada solicitud. La aplicación puede validar el token entrante contra una tabla de tokens de API válidos y “autenticar” la solicitud como realizada por el usuario asociado con ese token de API.
Laravel incluye servicios de autenticación y sesión integrados, que normalmente se acceden a través de las fachadas Auth y Session. Estas características proporcionan autenticación basada en cookies para solicitudes que se inician desde navegadores web. Proporcionan métodos que te permiten verificar las credenciales de un usuario y autenticar al usuario. Además, estos servicios almacenarán automáticamente los datos de autenticación adecuados en la sesión del usuario y emitirán la cookie de sesión del usuario.
Servicios de Autenticación para APIs
Laravel trae dos paquetes para ayudarte a manejar los API tokens y autenticar las request hechas con api tokens. Passport and Sanctum
Si se reciben peticiones tanto del navegador como por API, se pueden usar tanto el sistema basado con cookies, para las peticiones que se realicen desde un navegador, como Passport o Sanctum para los que no vienen de un navegador. No son excluyentes.
Passport
Passport es un proveedor de autenticación OAuth2 que ofrece una variedad de “tipos de concesión” de OAuth2 que le permiten emitir varios tipos de tokens. En general, este es un paquete robusto y complejo para la autenticación API. Sin embargo, la mayoría de las aplicaciones no requieren las funciones complejas que ofrece la especificación OAuth2, lo que puede resultar confuso tanto para los usuarios como para los desarrolladores. Además, históricamente los desarrolladores han estado confundidos acerca de cómo autenticar aplicaciones SPA o aplicaciones móviles utilizando proveedores de autenticación OAuth2 como Passport.
Sanctum
Laravel Sanctum es un paquete de autenticación híbrido web/API que puede gestionar todo el proceso de autenticación de su aplicación. Esto es posible porque cuando las aplicaciones basadas en Sanctum reciben una solicitud, Sanctum primero determinará si la solicitud incluye una cookie de sesión que haga referencia a una sesión autenticada. Sanctum logra esto llamando a los servicios de autenticación integrados de Laravel que comentamos anteriormente. Si la solicitud no se autentica mediante una cookie de sesión, Sanctum inspeccionará la solicitud en busca de un token API. Si hay un token API presente, Sanctum autenticará la solicitud utilizando ese token. Para obtener más información sobre este proceso, consulte la documentación sobre “cómo funciona” de Sanctum .
Sanctum es el encargado de comprobar que en la cookie recibida estan los datos de autenticación usando las fachadas Auth y Session .
Resumen y que opción elegir
- Para aplicaciones monolíticas, tanto el front como el back, estan en la aplicación, usar los servicios que trae por defecto laravel.
- Si tu aplicación va a funcionar como una api, usar sactum o passport
- Si estás construyendo una aplicación de una sola página (SPA) que será impulsada por un backend de Laravel, deberías usar Laravel Sanctum. Cuando uses Sanctum, deberás implementar manualmente tus propias rutas de autenticación en el backend o utilizar Laravel Fortify como un servicio de backend de autenticación que proporciona rutas y controladores para funciones como registro, restablecimiento de contraseña, verificación de correo electrónico, 2fa y más. https://laravel.com/docs/10.x/authentication#authenticating-users
Authentication Quickstart
Esta parte de la documentación trata sobre autenticar usuarios a través de los kits de inicio de aplicaciones de Laravel, que incluyen interfaces de usuario para ayudarte a comenzar rápidamente. Si deseas integrar manualmente consulta la documentación sobre la autenticación manual de usuarios más abajo.
Install a Starter Kit
Primero, deberías instalar un kit inicial. Laravel Breeze y Laravel Jetstream, ofrecen puntos de partida diseñados para incorporar la autenticación en tu aplicación Laravel.
Laravel Breeze es una implementación mínima y sencilla de todas las características de autenticación de Laravel, que incluye inicio de sesión, registro, reseteo de contraseña, verificación de correo electrónico y confirmación de contraseña. La capa de vistas de Breeze está compuesta por simples plantillas Blade estilizadas con Tailwind CSS. Además, Breeze proporciona opciones de estructura basadas en Livewire o Inertia, con la posibilidad de utilizar Vue o React para la estructura basada en Inertia.
Laravel Jetstream es un kit de inicio de aplicación más robusto que incluye soporte para estructurar tu aplicación con Livewire o Inertia y Vue. Además, Jetstream cuenta opcionalmente con soporte para autenticación de dos factores, equipos, gestión de perfil, gestión de sesiones del navegador, soporte para API a través de Laravel Sanctum, eliminación de cuentas y más.(trae más cosas)
Retrieving the Authenticated User
A menudo necesitarás interactuar con el usuario actualmente autenticado. Puedes acceder al usuario autenticado a través del método user de la fachada Auth
use Illuminate\Support\Facades\Auth;
// Retrieve the currently authenticated user...
$user = Auth::user();
// Retrieve the currently authenticated user's ID...
$id = Auth::id();
Alternativa: Obtener el usuario a traves de Illuminate\Http\Request
public function update(Request $request): RedirectResponse
{
$user = $request->user();
// ...
return redirect('/flights');
}
Determining if the Current User is Authenticated
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// The user is logged in...
}
Aunque es posible determinar si un usuario está autenticado utilizando el método
check, normalmente se utiliza un middleware para verificar que el usuario esté autenticado antes de permitirle acceder a ciertas rutas/controladores. Para obtener más información sobre esto, consulta la documentación sobre protección de rutas.
Protecting Routes
Laravel viene con un middleware llamado auth, que hace referencia a la clase Illuminate\\Auth\\Middleware\\Authenticate. Dado que este middleware ya está registrado en el kernel HTTP de tu aplicación, lo único que debes hacer es adjuntar el middleware a la definición de una ruta.
Route::get('/flights', function () {
// Only authenticated users may access this route...
})->middleware('auth');
Cuando el middleware auth detecta a un usuario no autenticado, redireccionará al usuario a la ruta con nombre login. Puedes modificar este comportamiento actualizando la función redirectTo en el archivo app/Http/Middleware/Authenticate.php de tu aplicación.
use Illuminate\Http\Request;
/**
* Get the path the user should be redirected to.
*/
protected function redirectTo(Request $request): string
{
return route('login');
}
Specifying a Guard
Cuando se adjunta el middleware auth a una ruta, también se puede especificar qué “guard” se debe usar para autenticar al usuario. La “guard” especificada debe corresponder a una de las claves en el array guards de tu archivo de configuración auth.php.
Route::get('/flights', function () {
// Only authenticated users may access this route...
})->middleware('auth:admin');
Throttling
Si estás utilizando los paquetes iniciales Laravel Breeze o Laravel Jetstream [starter kits], se aplicará automáticamente un límite de velocidad a los intentos de inicio de sesión. Por defecto, el usuario no podrá iniciar sesión durante un minuto si no proporciona las credenciales correctas después de varios intentos. El control es único para el nombre de usuario / dirección de correo electrónico del usuario y su dirección IP.
Si deseas limitar la velocidad de otras rutas en tu aplicación, consulta la documentación sobre limitación de velocidad.(rate limiting documentation.)
Manually Authenticating Users
Si decides no usar los starter kits, deberás manejar el inicio de sesión
Accederemos a los servicios de autenticación de Laravel a través de la fachada Auth, por lo que debemos asegurarnos de importar la fachada Auth en la parte superior de la clase. A continuación, veamos el método attempt. Normalmente, el método attempt se utiliza para manejar intentos de autenticación desde el formulario de “inicio de sesión” de tu interfaz. Si la autenticación es exitosa, debes regenerar la sesión del usuario para prevenir la fijación de sesión.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
/**
* Handle an authentication attempt.
*/
public function authenticate(Request $request): RedirectResponse
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return redirect()->intended('dashboard');
}
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
])->onlyInput('email');
}
}
El método attempt acepta un array de pares de clave/valor como su primer argumento. Los valores en el array se utilizarán para encontrar al usuario en la tabla de tu base de datos. Entonces, en el ejemplo mencionado anteriormente, el usuario se recuperará por el valor de la columna de correo electrónico (email). Si se encuentra el usuario, se comparará la contraseña hash almacenada en la base de datos con el valor de contraseña pasado al método a través del array. No debes hashear el valor de la contraseña entrante de la solicitud, ya que el framework automáticamente hasheará el valor antes de compararlo con la contraseña hash en la base de datos. Se iniciará una sesión autenticada para el usuario si las dos contraseñas hasheadas coinciden.
Recuerda que los servicios de autenticación de Laravel recuperarán usuarios de tu base de datos en base a la configuración del “provider” de tu “guard” de autenticación. En el archivo de configuración config/auth.php por defecto, se especifica el proveedor de usuario Eloquent y se indica que use el modelo App\Models\User para recuperar usuarios. Puedes cambiar estos valores dentro de tu archivo de configuración según las necesidades de tu aplicación.
El método attempt devolverá true si la autenticación fue exitosa. De lo contrario, devolverá false.
El método intended proporcionado por el redireccionador de Laravel redirigirá al usuario a la URL a la que intentaba acceder antes de ser interceptado por el middleware de autenticación. Se puede proporcionar una URI de respaldo a este método en caso de que el destino previsto no esté disponible.
Specifying Additional Conditions
Si lo deseas, también puedes agregar condiciones adicionales a la consulta de autenticación además del correo electrónico y la contraseña del usuario. Para lograr esto, simplemente podemos agregar las condiciones de consulta al array pasado al método attempt. Por ejemplo, podemos verificar que el usuario esté marcado como ‘activo’.
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// Authentication was successful...
}
Para condiciones de consulta complejas, puedes proporcionar una closure en tu array de credenciales. Esta closure se invocará con la instancia de la consulta, permitiéndote personalizar la consulta según las necesidades de tu aplicación.
use Illuminate\Database\Eloquent\Builder;
if (Auth::attempt([
'email' => $email,
'password' => $password,
fn (Builder $query) => $query->has('activeSubscription'),
])) {
// Authentication was successful...
}
El método attemptWhen, que recibe una closure como su segundo argumento, puede ser utilizado para realizar una inspección más exhaustiva del usuario potencial antes de autenticarlo. La closure recibe al usuario potencial y debe devolver true o false para indicar si el usuario puede ser autenticado.
if (Auth::attemptWhen([
'email' => $email,
'password' => $password,
], function (User $user) {
return $user->isNotBanned();
})) {
// Authentication was successful...
}
Accessing Specific Guard Instances
A través del método guard del facade Auth, puedes especificar qué instancia de guardia te gustaría utilizar al autenticar al usuario. Esto te permite gestionar la autenticación para diferentes partes de tu aplicación utilizando modelos o tablas de usuario completamente separadas.
El nombre del “guard” pasado al método guard debe corresponder a uno de los guardias configurados en tu archivo de configuración auth.php:
if (Auth::guard('admin')->attempt($credentials)) {
// ...
}
Remembering Users
Muchas aplicaciones web proporcionan “remember me” en su formulario de inicio de sesión. Si deseas ofrecer funcionalidad de “remember me” en tu aplicación, puedes pasar un valor booleano como segundo argumento al método attempt.
Cuando este valor es true, Laravel mantendrá al usuario autenticado indefinidamente o hasta que cierre sesión manualmente. La tabla de User debe incluir la columna remember_token de tipo string, la cual se utilizará para almacenar el token de “remember_me”. La migración de la tabla de User ya incluye esta columna.
use Illuminate\Support\Facades\Auth;
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
// The user is being remembered...
}
Si tu aplicación ofrece la funcionalidad “remember me”, puedes utilizar el método viaRemember para determinar si el usuario actualmente autenticado lo fue usando “remember me”
use Illuminate\Support\Facades\Auth;
if (Auth::viaRemember()) {
// ...
}
Other Authentication Methods
Authenticate a User Instance
Si necesitas autenticar a una instancia de User, puedes pasar la instancia de usuario al método login de la fachada Auth. La instancia de usuario proporcionada debe ser una implementación del contrato Illuminate\Contracts\Auth\Authenticatable. El modelo App\Models\User incluido en Laravel ya implementa esta interfaz. Este método de autenticación es útil cuando ya tienes una instancia válida de usuario, por ejemplo, justo después de que un usuario se registra en tu aplicación.
use Illuminate\Support\Facades\Auth;
Auth::login($user);
Puedes pasar un valor booleano al método login si se desea que el usuario sea recordado, autenticando al usuario de manera indeterminada o hasta que haga log out manualmente.
Auth::login($user, $remember = true);
Puedes especificar el guard al llamar al método login
Auth::guard('admin')->login($user);
Authenticate a User by ID
Para autenticar a un usuario usando el primary key de la base de datos, se puede usar el método loginUsingId
Auth::loginUsingId(1);
Puedes pasar un valor booleano como segundo argumento al método loginUsingId. Este valor indica si se desea la funcionalidad de “remember me” para la sesión autenticada. Recuerda que esto significa que la sesión estará autenticada indefinidamente o hasta que el usuario cierre sesión manualmente en la aplicación.
Authenticate a User Once
Puedes usar el método once para autenticar a un usuario en la aplicación por una única solicitud. No se utilizarán sesiones ni cookies al llamar a este método.
if (Auth::once($credentials)) {
// ...
}
HTTP Basic Authentication
La autenticación básica HTTP proporciona una forma rápida de autenticar usuarios en tu aplicación sin necesidad de configurar una página de “inicio de sesión” dedicada. Para comenzar, adjunta el middleware auth.basic a una ruta en Laravel. Este middleware está incluido por defecto en el framework Laravel, por lo que no necesitas definirlo tú mismo.
Route::get('/profile', function () {
// Only authenticated users may access this route...
})->middleware('auth.basic');
Una vez que el middleware auth.basic ha sido adjuntado a una ruta en Laravel, automáticamente se te pedirán credenciales al intentar acceder a esa ruta en tu navegador. Por defecto, el middleware auth.basic asume que la columna email en la tabla users de tu base de datos es el “nombre de usuario” del usuario.
A Note on FastCGI
Si estás utilizando PHP FastCGI y Apache para servir tu aplicación Laravel, es posible que la autenticación básica HTTP no funcione correctamente. Para corregir estos problemas, puedes agregar las siguientes líneas al archivo .htaccess de tu aplicación:
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
Stateless HTTP Basic Authentication
También puedes utilizar la autenticación básica HTTP sin establecer una cookie de identificación de usuario en la sesión. Esto es especialmente útil si decides utilizar la autenticación HTTP para autenticar las solicitudes a la API de tu aplicación. Para lograr esto, define un middleware que llame al método onceBasic. Si el método onceBasic no devuelve ninguna respuesta, la solicitud puede continuar siendo procesada por la aplicación.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class AuthenticateOnceWithBasicAuth
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return Auth::onceBasic() ?: $next($request);
}
}
A continuación, adjunte el middleware a una ruta:
Route::get('/api/user', function () {
// Only authenticated users may access this route...
})->middleware(AuthenticateOnceWithBasicAuth::class);
Logging Out
Para cerrar sesión manualmente a los usuarios de tu aplicación, puedes utilizar el método logout proporcionado por la fachada Auth. Esto eliminará la información de autenticación de la sesión del usuario, de modo que las solicitudes subsiguientes no estarán autenticadas.
Además de llamar al método logout, se recomienda invalidar la sesión del usuario y regenerar su token CSRF. Después de cerrar sesión, normalmente se redirige al usuario a la ruta root de la aplicación.
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
/**
* Log the user out of the application.
*/
public function logout(Request $request): RedirectResponse
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
Invalidating Sessions on Other Devices
Laravel también proporciona un mecanismo para invalidar y “cerrar sesión” en las sesiones de usuario activas en otros dispositivos sin invalidar la sesión en su dispositivo actual. Este feature se utiliza típicamente cuando un usuario está cambiando o actualizando su contraseña y deseas invalidar las sesiones en otros dispositivos mientras mantienes autenticado el dispositivo actual del usuario.
Antes de comenzar, asegúrate de que el middleware Illuminate\Session\Middleware\AuthenticateSession esté incluido en las rutas que requieran autenticación de sesión. Normalmente, puedes colocar este middleware en la definición de un grupo de rutas para que se aplique a la mayoría de las rutas de tu aplicación. Por defecto, el middleware AuthenticateSession puede ser adjuntado a una ruta utilizando el alias de middleware auth.session
Route::middleware(['auth', 'auth.session'])->group(function () {
Route::get('/', function () {
// ...
});
});
Luego, puedes utilizar el método logoutOtherDevices proporcionado por la fachada Auth. Este método requiere que el usuario confirme su contraseña actual, la cual tu aplicación debería aceptar a través de un formulario de entrada:
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($currentPassword);
Cuando se invoca el método logoutOtherDevices en Laravel, las otras sesiones del usuario serán invalidadas por completo, lo que significa que serán “cerradas” en todos los guards por los cuales estaban autenticados previamente.
Password Confirmation
Al construir tu aplicación, es posible que ocasionalmente tengas acciones que requieran que el usuario confirme su contraseña antes de que se realice la acción o antes de redirigir al usuario a una área sensible de la aplicación. Laravel incluye middleware integrado para facilitar este proceso. Implementar esta función requerirá que definas dos rutas: una ruta para mostrar una vista que solicite al usuario confirmar su contraseña y otra ruta para confirmar que la contraseña es válida y redirigir al usuario a su destino previsto.
Configuration
Después de confirmar su contraseña, a un usuario no se le pedirá que confirme su contraseña nuevamente durante tres horas. Sin embargo, puedes configurar el tiempo antes de que se vuelva a solicitar al usuario que confirme su contraseña cambiando el valor de la configuración password_timeout dentro del archivo de configuración config/auth.php de tu aplicación
Routing
The Password Confirmation Form
Primero mostraremos la vista donde estará el formulario donde el usuario confirmara su password.
Route::get('/confirm-password', function () {
return view('auth.confirm-password');
})->middleware('auth')->name('password.confirm');
Confirming the Password
A continuación, definiremos una ruta que manejará la solicitud del formulario desde la vista de “confirmar contraseña”. Esta ruta será responsable de validar la contraseña y redirigir al usuario a su destino previsto.
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
Route::post('/confirm-password', function (Request $request) {
if (! Hash::check($request->password, $request->user()->password)) {
return back()->withErrors([
'password' => ['The provided password does not match our records.']
]);
}
$request->session()->passwordConfirmed();
return redirect()->intended();
})->middleware(['auth', 'throttle:6,1']);
Antes de continuar, examinemos esta ruta con más detalle. Primero, se determina que el campo de contraseña de la solicitud realmente coincide con la contraseña del usuario autenticado. Si la contraseña es válida, necesitamos informar a la sesión de Laravel que el usuario ha confirmado su contraseña. El método passwordConfirmed establecerá una marca de tiempo en la sesión del usuario que Laravel puede utilizar para determinar cuándo fue la última vez que el usuario confirmó su contraseña. Finalmente, podemos redirigir al usuario a su destino previsto.
Protecting Routes
Debes asegurarte de que cualquier ruta que realice una acción que requiera una confirmación reciente de la contraseña esté asignada al middleware password.confirm. Este middleware está incluido en la instalación predeterminada de Laravel y almacenará automáticamente el destino previsto del usuario en la sesión, para que el usuario pueda ser redirigido a esa ubicación después de confirmar su contraseña. Después de almacenar el destino previsto del usuario en la sesión, el middleware redirigirá al usuario a la ruta con nombre password.confirm.
Route::get('/settings', function () {
// ...
})->middleware(['password.confirm']);
Route::post('/settings', function () {
// ...
})->middleware(['password.confirm']);
Adding Custom Guards
Puedes definir tus propios guards de autenticación utilizando el método extend en la fachada Auth. Debes colocar tu llamada al método extend dentro de un proveedor de servicios. Dado que Laravel ya incluye un AppServiceProvider, podemos colocar el código en ese proveedor
<?php
namespace App\Providers;
use App\Services\Auth\JwtGuard;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
// ...
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Auth::extend('jwt', function (Application $app, string $name, array $config) {
// Return an instance of Illuminate\Contracts\Auth\Guard...
return new JwtGuard(Auth::createUserProvider($config['provider']));
});
}
}
Como puedes ver en el ejemplo anterior, el callback pasado al método extend debe retornar una implementación de Illuminate\Contracts\Auth\Guard. Esta interfaz contiene algunos métodos que necesitarás implementar para definir un guard personalizado. Una vez que hayas definido tu guard personalizado, puedes referenciarlo en la configuración de guards dentro del archivo de configuración auth.php:
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
Closure Request Guards
La forma más sencilla de implementar un sistema de autenticación personalizado basado en solicitudes HTTP es utilizando el método Auth::viaRequest. Este método te permite definir rápidamente tu proceso de autenticación usando un solo cierre (closure).
Para comenzar, llama al método Auth::viaRequest dentro del método boot de AppServiceProvider de tu aplicación. El método viaRequest acepta el nombre del driver de autenticación como primer argumento. Este nombre puede ser cualquier cadena que describa tu guardia personalizado. El segundo argumento que se pasa al método debe ser un cierre que reciba la solicitud HTTP entrante y devuelva una instancia de usuario o, si la autenticación falla, null:
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Auth::viaRequest('custom-token', function (Request $request) {
return User::where('token', (string) $request->token)->first();
});
}
Una vez que hayas definido tu controlador de autenticación personalizado, puedes configurarlo como un guardia dentro de la configuración de guards en tu archivo de configuración auth.php:
'guards' => [
'api' => [
'driver' => 'custom-token',
],
],
Finalmente, puedes hacer referencia al “guard” al asignar el middleware de autenticación a una ruta:
Route::middleware('auth:api')->group(function () {
// ...
});
Adding Custom User Providers
Si no estás utilizando una base de datos relacional tradicional para almacenar tus usuarios, necesitarás extender Laravel con tu propio proveedor de usuarios para la autenticación. Utilizaremos el método provider en la fachada Auth para definir un proveedor de usuarios personalizado. El resolver del proveedor de usuarios debe devolver una implementación de Illuminate\Contracts\Auth\UserProvider:
<?php
namespace App\Providers;
use App\Extensions\MongoUserProvider;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
// ...
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Auth::provider('mongo', function (Application $app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new MongoUserProvider($app->make('mongo.connection'));
});
}
}
Después de haber registrado el proveedor utilizando el método provider, puedes cambiar al nuevo proveedor de usuarios en tu archivo de configuración auth.php. Primero, define un proveedor que utilice tu nuevo driver:
'providers' => [
'users' => [
'driver' => 'mongo',
],
],
Finalmente, puedes hacer referencia a este proveedor en la configuración de tus guards:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
The User Provider Contract
Las implementaciones de Illuminate\Contracts\Auth\UserProvider son responsables de obtener una implementación de Illuminate\Contracts\Auth\Authenticatable desde un sistema de almacenamiento persistente, como MySQL, MongoDB, etc. Estas dos interfaces permiten que los mecanismos de autenticación de Laravel sigan funcionando independientemente de cómo se almacenen los datos del usuario o qué tipo de clase se use para representar al usuario autenticado:
Echemos un vistazo al contrato Illuminate\Contracts\Auth\UserProvider:
<?php
namespace Illuminate\Contracts\Auth;
interface UserProvider
{
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(Authenticatable $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(Authenticatable $user, array $credentials);
public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false);
}
- La función retrieveById típicamente recibe una clave que representa al usuario, como un ID autoincremental de una base de datos MySQL. La implementación de Authenticatable que coincida con el ID debe ser recuperada y devuelta por este método.
- La función retrieveByToken recupera un usuario por su identificador único $identifier y el $token de “recordar sesión”, típicamente almacenado en una columna de base de datos como remember_token. Al igual que en el método anterior, se debe devolver la implementación de Authenticatable que coincida con el valor del token.
- El método updateRememberToken actualiza el remember_token del usuario $user con el nuevo $token. Se asigna un nuevo token a los usuarios en un intento de autenticación exitoso de “recordar sesión” o cuando el usuario cierra sesión.
- El método retrieveByCredentials recibe el array de credenciales pasado al método Auth::attempt al intentar autenticar con la aplicación. El método debe “consultar” el almacenamiento persistente subyacente para el usuario que coincida con esas credenciales. Típicamente, este método ejecutará una consulta con una condición “where” que busca un registro de usuario con un “username” que coincida con el valor de $credentials[‘username’]. El método debe devolver una implementación de Authenticatable. Este método no debe intentar validar ni autenticar la contraseña.
- El método validateCredentials debería comparar el $user dado con las $credentials para autenticar al usuario. Por ejemplo, este método típicamente usará el método Hash::check para comparar el valor de $user->getAuthPassword() con el valor de $credentials[‘password’]. Este método debe devolver true o false indicando si la contraseña es válida.
- El método rehashPasswordIfRequired debería rehashear la contraseña del $user dado si es necesario y es compatible. Por ejemplo, este método típicamente usará el método Hash::needsRehash para determinar si se necesita rehashear el valor de $credentials[‘password’]. Si la contraseña necesita ser rehasheada, el método debería usar el método Hash::make para rehashear la contraseña y actualizar el registro del usuario en el almacenamiento persistente subyacente.
The Authenticatable Contract
Ahora que hemos explorado cada uno de los métodos en UserProvider, echemos un vistazo al contrato Authenticatable. Recuerda, los proveedores de usuarios deben devolver implementaciones de esta interfaz desde los métodos retrieveById, retrieveByToken y retrieveByCredentials:
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable
{
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPasswordName();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}
Esta interfaz es simple. El método getAuthIdentifierName debería devolver el nombre de la columna “clave primaria” para el usuario y el método getAuthIdentifier debería devolver la “clave primaria” del usuario. Cuando se usa un backend MySQL, esto probablemente sería la clave primaria autoincremental asignada al registro del usuario. El método getAuthPasswordName debería devolver el nombre de la columna de contraseña del usuario. El método getAuthPassword debería devolver la contraseña hasheada del usuario.
Esta interfaz permite que el sistema de autenticación funcione con cualquier clase de “usuario”, independientemente de qué ORM o capa de abstracción de almacenamiento estés utilizando. Por defecto, Laravel incluye una clase App\Models\User en el directorio app/Models que implementa esta interfaz.
Automatic Password Rehashing
El algoritmo de hashing de contraseñas predeterminado de Laravel es bcrypt. El “factor de trabajo” para los hashes bcrypt se puede ajustar a través del archivo de configuración config/hashing.php de tu aplicación o la variable de entorno BCRYPT_ROUNDS.
Típicamente, el factor de trabajo bcrypt debería incrementarse con el tiempo a medida que aumenta la potencia de procesamiento de CPU/GPU. Si aumentas el factor de trabajo bcrypt para tu aplicación, Laravel rehashearán automáticamente y con gracia las contraseñas de los usuarios a medida que los usuarios se autentiquen con la aplicación a través de Laravel o cuando autentiques manualmente a los usuarios a través del método attempt.
Típicamente, el rehasheo automático de contraseñas no debería interrumpir tu aplicación. Sin embargo, podrías desactivar este comportamiento publicando el archivo de configuración de rehashing:
php artisan config:publish hashing
Una vez que el archivo de configuración se haya publicado, podrás configurar el valor de configuración de rehash_on_login a false:
'rehash_on_login' => false,
Events
Laravel envía una variedad de eventos durante el proceso de autenticación. Podrías definir listeners para cualquiera de los siguientes eventos:
Illuminate\Auth\Events\Registered
Illuminate\Auth\Events\Attempting
Illuminate\Auth\Events\Authenticated
Illuminate\Auth\Events\Login
Illuminate\Auth\Events\Failed
Illuminate\Auth\Events\Validated
Illuminate\Auth\Events\Verified
Illuminate\Auth\Events\Logout
Illuminate\Auth\Events\CurrentDeviceLogout