Modificar las redirecciones de inicio de sesión en Jetstream o Fortify
- Publicado el 14 agosto, 2024
- Palabras: 920
Recientemente, estaba trabajando en un proyecto con Laravel Jetstream y me encontré con un escenario en el que necesitaba redirigir a los usuarios a una ruta diferente. Imagina que tienes usuarios y administradores y los administradores tienen un panel especial que solo ellos pueden ver. Por lo general, prefiero redirigir a los administradores a su panel especial cuando inician sesión.
Al usar Laravel Jetstream o Fortify, no resulta inmediatamente evidente cómo hacer esto, especialmente cuando se usa la autenticación de dos factores.
#Cómo funciona la autenticación en Jetstream y Fortify
Jetstream utiliza Laravel Fortify en segundo plano, por lo que el proceso es exactamente el mismo para las aplicaciones que ejecutan Fortify por sí solas y para los proyectos que ejecutan Jetstream.
Fortify utiliza canales de acción para enrutar cada solicitud a través de una serie de clases que se encargan de una sola tarea, como intentar autenticar al usuario o redirigirlo si tiene configurada la autenticación de dos factores.
#Cómo anular el paso de redirección
Fortify te permite personalizar completamente estas canalizaciones si lo necesitas, pero hay una forma más sencilla de anular el paso de redirección.
El último paso de la canalización de autenticación toma la clase Laravel\Fortify\Contracts\LoginResponse del contenedor de servicios y la devuelve. Eso significa que podemos anular la clase LoginResponse con una clase LoginResponse personalizada y realizar las redirecciones personalizadas allí.
La clase LoginResponse predeterminada se ve así:
<?php
namespace Laravel\Fortify\Http\Responses;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class LoginResponse implements LoginResponseContract
{
/**
* Create an HTTP response that represents the object.
*
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function toResponse($request)
{
return $request->wantsJson()
? response()->json(['two_factor' => false])
: redirect()->intended(config('fortify.home'));
}
}
Dado que Fortify utiliza acciones que realizan una sola tarea, el paso LoginResponse es realmente claro y simple.
Para personalizar las redirecciones, primero agreguemos nuestra clase LoginResponse personalizada en el directorio app/Http/Responses. Luego, podemos personalizar el método toResponse para redirigir al usuario a diferentes rutas según el tipo de usuario que sea.
<?php
namespace App\Http\Responses;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class LoginResponse implements LoginResponseContract
{
/**
* @param $request
* @return mixed
*/
public function toResponse($request)
{
$home = auth()->user()->is_admin ? '/admin' : '/dashboard';
return redirect()->intended($home);
}
}
Luego, en FortifyServiceProvider, necesitamos vincular nuestra clase LoginResponse personalizada para anular el valor predeterminado que se proporciona con Fortify.
<?php
namespace App\Providers;
// ...
use App\Http\Responses\LoginResponse;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
// ...
$this->app->singleton(LoginResponseContract::class, LoginResponse::class);
}
}
#Autenticación de dos factores
Esto funciona casi a la perfección para mis necesidades. Sin embargo, falta una pieza: la autenticación de dos factores. Si un usuario tiene habilitada la autenticación de dos factores e inicia sesión, Fortify devuelve una clase de respuesta diferente. Afortunadamente, la clase de autenticación de dos factores también está vinculada al contenedor de servicios. Esta vez, necesitaremos anular la clase Laravel\Fortify\Http\Responses\TwoFactorLoginResponse en el contenedor. Agregar un par de líneas más a FortifyServiceProvider debería resolver el problema.
<?php
namespace App\Providers;
// ...
use App\Http\Responses\LoginResponse;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
// ...
$this->app->singleton(LoginResponseContract::class, LoginResponse::class);
$this->app->singleton(TwoFactorLoginResponseContract::class, LoginResponse::class);
}
}
Nota: Estoy reemplazando la clase TwoFactorLoginResponse con la misma clase LoginResponse personalizada ya que la funcionalidad debería ser exactamente la misma.
#Anulación de otras funciones de Jetstream y Fortify
Otras funciones de Jetstream y Fortify se pueden personalizar de una manera muy similar. Si busca en el FortifyServiceProvider incluido en el paquete (no en el específico de su proyecto) y se desplaza hacia abajo hasta el método registerResponseBindings, debería ver algo similar a esto:
<?php
namespace Laravel\Fortify;
// ...
class FortifyServiceProvider extends ServiceProvider
{
// ...
/**
* Register the response bindings.
*
* @return void
*/
protected function registerResponseBindings()
{
$this->app->singleton(FailedPasswordConfirmationResponseContract::class, FailedPasswordConfirmationResponse::class);
$this->app->singleton(FailedPasswordResetLinkRequestResponseContract::class, FailedPasswordResetLinkRequestResponse::class);
$this->app->singleton(FailedPasswordResetResponseContract::class, FailedPasswordResetResponse::class);
$this->app->singleton(FailedTwoFactorLoginResponseContract::class, FailedTwoFactorLoginResponse::class);
$this->app->singleton(LockoutResponseContract::class, LockoutResponse::class);
$this->app->singleton(LoginResponseContract::class, LoginResponse::class);
$this->app->singleton(TwoFactorLoginResponseContract::class, TwoFactorLoginResponse::class);
$this->app->singleton(LogoutResponseContract::class, LogoutResponse::class);
$this->app->singleton(PasswordConfirmedResponseContract::class, PasswordConfirmedResponse::class);
$this->app->singleton(PasswordResetResponseContract::class, PasswordResetResponse::class);
$this->app->singleton(RegisterResponseContract::class, RegisterResponse::class);
$this->app->singleton(SuccessfulPasswordResetLinkRequestResponseContract::class, SuccessfulPasswordResetLinkRequestResponse::class);
}
// ...
}
¡Eso significa que cada una de estas clases de respuesta se pueden anular en su proyecto si es necesario!
Antonio Jenaro
Web Developer
Fuente: Jason Beggs
Inicia la conversación
Hazte miembro de Antonio Jenaro para comenzar a comentar.
Regístrate ahora¿Ya estás registrado? Inicia sesión