Cómo configurar Laravel Fortify y personalizar su comportamiento para que funcione de la manera adecuada para el desarrollo de un API. Resolver problemas comunes de configuración de Fortify.
En los anteriores artículos del Manual de desarrollo de un API con Laravel Sanctum y Fortify hemos avanzado bastante en la realización del sistema de autenticación. Después de haber conocido e instalado en el artículo anterior Laravel Fortify, ahora tenemos que realizar algunas tareas de adaptación de Fortify según las necesidades de nuestro proyecto.
Las necesidades de nuestro proyecto vienen marcadas porque vamos a usar Fortify en el contexto de un API. Recuerda que Fortify no necesita necesariamente funcionar en un API, por lo que hay algunas configuraciones de casa que están más pensadas para sitios web. Tendremos que cambiarlas como verás a continuación y, de paso, nos dará pie a aprender algunas cosas más sobre este package de Laravel.
Configurar las funcionalidades de Fortify
En este paso vamos a editar el archivo de configuración del propio Fortify: config/fortify.php
. En él encontramos un array llamado "features
", el cual podemos activar o desactivar aquellas que nos interesen o no.
Si queremos las funcionalidades básicas de un sistema de autenticación, podríamos dejar algo así.
'features' => [
Features::registration(),
Features::resetPasswords(),
Features::emailVerification(),
// Features::updateProfileInformation(),
// Features::updatePasswords(),
// Features::twoFactorAuthentication([
// 'confirm' => true,
// 'confirmPassword' => true,
// // 'window' => 0,
// ]),
],
No te preocupes porque hayamos dejado de lado algunas de las funcionalidades ofrecidas por Fortfy. Las que no hemos activado todavía se podrían activar más adelante si fuera necesario.
Desactivar las vistas
Para el uso que vamos a hacer de nuestro backend necesitamos desactivar las vistas de la aplicación para lo que respecta a Fortify. Esto lo realizamos también mediante el archivo de configuración de Fortify. Dentro del archivo config/fortify.php
también buscamos el siguiente valor:
'views' => true,
Y lo cambiamos por
'views' => false,
En este punto es relevante comentar que la vista del "reset de la clave" si que la necesitaremos cuando activemos esa funcionalidad. La tendremos que activar manualmente en los archivos de rutas de nuestro proyecto backend con Laravel.
Este punto requiere más explicaciones para dejar claro cómo activar estas vistas. De todos modos, vamos a aplazar estas explicaciones más adelante cuando abordemos el flujo para recordar la clave.
Comportamiento de redirección si estás autenticado
Hay otra cosa que resulta molesta del comportamiento de Fortify, en el caso de querer usar el sistema como un servicio web (API). Se trata de la redirección a la ruta "/home" que se realiza cuando el usuario está autenticado e intenta hacer de nuevo un login.
Este comportamiento se debe a un middleware llamado RedirectIfAuthenticated
, que está en la ruta app/Http/Middleware/RedirectIfAuthenticated.php
.
Su código lo vamos a cambiar para que incluya este otro comportamiento, que permite detectar si estamos accediendo mediante Ajax a la ruta de login y, en caso que sea así, se envíe una respuesta en formato JSON.
El código que tenemos que añadir es este:
if ($request->expectsJson()) {
return response()->json(['error' => 'Ya estás autenticado.'], 200);
}
El método $request->expectsJson()
devuelve true
cuando se esté invocando el login desde una solicitud Ajax.
Esa comprobación la tenemos que poner dentro del bucle foreach, donde ahora el código quedará de esta manera.
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
if ($request->expectsJson()) {
return response()->json(['error' => 'Ya estás autenticado.'], 200);
}
return redirect(RouteServiceProvider::HOME);
}
}
Básicamente, lo que hemos hecho es que se envíe un mensaje indicando que ya tienes el usuario autenticado, por lo que no necesitarías acceder de nuevo a la ruta de login.
Este comportamiento lo podrías redefinir para que tu API devuelva la respuesta que tú necesites, con el código HTTP que te resulte adecuado.
Comportamiento si no estás autenticado
El middleware Authenticate
, en la ruta app/Http/Middleware/Authenticate.php
también sería interesante cambiarlo. Básicamente este middleware realiza el trabajo de enviar al usuario a la ruta donde debería hacer su autenticación, para cada ruta que configuremos que requiera estar logueado.
Vamos a cambiarlo para que redirija a la ruta del frontend donde se hace el login.
En principio tenemos este código.
protected function redirectTo(Request $request): ?string
{
return $request->expectsJson() ? null : route('login');
}
Podemos cambiarlo por este otro.
protected function redirectTo(Request $request): ?string
{
if (!$request->expectsJson()) {
return url(env('FRONTEND_URL') . '/login');
}
return null;
}
Si te fijas, estamos usando una variable de entorno nueva, por lo que necesitarás crearla en el archivo .env
. La variable de entorno FRONTEND_URL
deberá tener la ruta donde tienes la aplicación frontend.
El valor de la variable de entorno podría ser algo como esto:
FRONTEND_URL=http://localhost:8000
Problemas comunes de la configuración de Laravel Fortify
Ahora voy a señalar algunos problemas comunes que he encontrado a la hora de dar estos primeros pasos en la configuración de Laravel Fortify, con sus soluciones.
Solucionar 401 (Unauthorized) en Fortify
Durante el proceso de creación de tu sistema de login puedes apreciar un mensaje 401 (Unauthorized) cuando intentas acceder a una ruta para la cual necesitas estar autenticado.
Esta no debería ser la respuesta que el API te debería entregar, en el caso que ya hayas hecho login. Si has verificado que tu sesión está activa, porque hayas hecho un registro o login satisfactorio y aún así sigues recibiendo este mensaje puede deberse a dos motivos:
- Qué el dominio de tu frontend, desde donde estás haciendo la solicitud no esté entre los que se permite el inicio de sesión con variables de sesión. Entonces debes de asegurarte que la variable de entorno
SANCTUM_STATEFUL_DOMAINS
contiene un valor correcto. Atención en este punto poque debemos colocar el valor sinhttp://
, que es uno de los errores típicos que pueden suceder. El valor es simplemente el nombre del dominio y el puerto, si es que estás usando un puerto personalizado. Por ejemplo:SANCTUM_STATEFUL_DOMAINS=localhost:8000
- Que no se estén creando las variables de sesión en el backend de manera correcta. En este caso debes asegurarte que no tienes la variable de sesión
SESSION_DOMAIN
en tu archivo.env
. O, en el caso de tenerla, que contenga el dominio de tu backend, sinhttp://
ohttps://
. Por ejemplo para desarrollo sería algo asíSESSION_DOMAIN=localhost
.
Solucionar has been blocked by CORS policy
Otro problema típico que te puede ocurrir es que las solicitudes se bloqueen por la política de CORS. En estos casos el acceso a las rutas te pueden entregar mensaje como este:
Access to XMLHttpRequest at 'http://localhost/sanctum/csrf-cookie' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Para solucionar este problema verifica:
- Que en
config/cors.php
tienes la ruta a la que quieres acceder en el array paths. - Que tienes el valor
allowed_origins
enconfig/cors.php
asignado a['*']
o en su defecto a los dominios donde está permitido el uso del API.
El valor de allowed_origins
podría estar definido, por ejemplo, de la siguiente manera:
'allowed_origins' => ['http://localhost:8000', 'https://escuela.it']
.
Conclusión a la configuración básica de Laravel Fortify
Hasta aquí hemos podido terminar la configuración de nuestro backend para que pueda realizarse la autenticación de usuarios, usando los packages oficiales de Laravel Sanctum y Laravel Fortify.
Por supuesto, estarás deseando probar tu backend y realizar las tareas de autenticación con él, para verificar que todo está funcionando correctamente. Para realizar esta tarea no podríamos utilizar directamente con el navegador, porque las solicitudes deben realizarse mediante Ajax, además de enviar los datos correctos al backend para realizar el registro, autenticación y autorización. Por ello en el próximo artículo vamos a detenernos para mostrar un medio de ejercitar nuestra API y mandar las solicitudes necesarias para ponerla en marcha.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...