Autenticación
Arrel autentica con Sanctum en modo SPA: cookies de sesión protegidas con CSRF, sin tokens que gestionar. Sobre esta base hay tres capas opcionales: la verificación del correo, un segundo factor y las notificaciones de la campana.
Configurar Sanctum
La aplicación debe añadir el dominio del panel a sanctum.stateful (y, en desarrollo, el origen del servidor de Vite si trabajas en modo dev):
config([
'sanctum.stateful' => array_merge(
config('sanctum.stateful', []),
['tu-dominio.test', 'localhost:5173'],
),
]);La API de autenticación vive bajo /arrel/api/, sea cual sea el prefijo del panel:
| Ruta | Qué hace |
|---|---|
POST /arrel/api/login | Inicia la sesión con email y password. |
POST /arrel/api/login/two-factor | Resuelve el segundo factor de un inicio de sesión pendiente. |
POST /arrel/api/logout | Cierra la sesión. |
GET /arrel/api/user | El usuario autenticado. |
El resto de la API queda detrás de auth:sanctum, la verificación del correo y el segundo factor.
Límites de intentos
- El inicio de sesión admite cinco intentos fallidos por combinación de correo y dirección IP. Pasado el límite, la respuesta es un error de validación con el mensaje
arrel::auth.throttle. - Un inicio de sesión que espera el segundo factor caduca a los cinco minutos, o tras cinco códigos incorrectos. El usuario debe volver a escribir correo y contraseña.
- Los endpoints de login tienen además un límite de 10 peticiones por minuto a nivel de ruta.
Verificación del correo
Si el modelo de usuario implementa Illuminate\Contracts\Auth\MustVerifyEmail, el panel no se abre hasta que el correo está verificado. Mientras no lo está, la API responde 403 con email_verification_required: true y la SPA muestra la pantalla de verificación, con un botón para enviar el correo (limitado a tres por minuto).
final class User extends Authenticatable implements MustVerifyEmail
{
// ...
}El enlace del correo es una URL firmada y temporal. Caduca según auth.verification.expire (60 minutos por defecto), apunta a arrel.email.verify y, una vez verificado, redirige de nuevo al panel. Un usuario que no implementa MustVerifyEmail no pasa nunca por este paso.
Segundo factor
Arrel no lleva ninguna implementación de TOTP propia. Define el contrato Arrel\Auth\TwoFactorAuthenticator y tú enlazas la que quieras (un paquete de 2FA, una implementación propia sobre un secreto cifrado...).
namespace Arrel\Auth;
interface TwoFactorAuthenticator
{
public function isEnabledFor(Authenticatable $user): bool;
public function isRequiredFor(Authenticatable $user): bool;
public function verify(Authenticatable $user, string $code): bool;
public function newSecret(): string;
public function qrCode(Authenticatable $user, string $secret): string;
public function verifySetup(string $secret, string $code): bool;
/** @return list<string> Los códigos de recuperación, para mostrarlos una sola vez. */
public function enable(Authenticatable $user, string $secret): array;
public function disable(Authenticatable $user): void;
}| Método | Cuándo se llama |
|---|---|
isEnabledFor() | En el inicio de sesión, para decidir si hay que pedir un código. |
isRequiredFor() | Para obligar a un usuario concreto a activarlo antes de entrar en el panel (por ejemplo, según su rol). |
verify() | Al validar el código del inicio de sesión. Debe aceptar también un código de recuperación. |
newSecret(), qrCode() | Al empezar la activación. qrCode() devuelve la imagen que la SPA muestra tal cual. |
verifySetup() | Al confirmar la activación, con el secreto todavía pendiente en la sesión. |
enable() | Una vez confirmado. Guarda el secreto y devuelve los códigos de recuperación. |
disable() | Al desactivarlo. |
Para activarlo, enlaza tu implementación en el contenedor:
// AppServiceProvider::register()
$this->app->bind(TwoFactorAuthenticator::class, TotpAuthenticator::class);Sin ningún enlace, el segundo factor no existe: no hay ningún paso adicional ni ninguna página de seguridad que usar.
Cómo lo ve el usuario
- En el inicio de sesión, si
isEnabledFor()es cierto, la respuesta es{ "two_factor": true }y la SPA pide el código. - La página de seguridad (
/{prefix}/{panel}/security) permite activarlo y desactivarlo. Al activarlo muestra el QR, pide un primer código y, una vez confirmado, muestra los códigos de recuperación una única vez. - Si
isRequiredFor()es cierto y el usuario todavía no lo ha activado, toda la API responde 403 contwo_factor_setup_required: truey la SPA lo lleva a la página de seguridad. Los endpoints de la propia página de seguridad siguen accesibles. - Un usuario para el que es obligatorio no puede desactivarlo: el endpoint responde 403 con
arrel::auth.required_cannot_disable.
Los endpoints son GET y DELETE /arrel/api/two-factor, POST /arrel/api/two-factor/setup y POST /arrel/api/two-factor/confirm. La confirmación y la desactivación tienen un límite de 10 peticiones por minuto.
Middleware antes y después del usuario
config('arrel.middleware') se ejecuta antes de que Sanctum resuelva la sesión: es el lugar para identificar el tenant. config('arrel.authenticated_middleware') se ejecuta después de la verificación del correo y del segundo factor, con el usuario ya resuelto. Véase Configuración.
Notificaciones
La campana del panel lee las notificaciones de base de datos de Laravel del usuario autenticado. No hace falta nada específico de Arrel: basta con una notificación que use el canal database y guarde estas claves en data:
final class PostPublished extends Notification
{
public function __construct(private readonly Post $post) {}
public function via(object $notifiable): array
{
return ['database'];
}
public function toArray(object $notifiable): array
{
return [
'title' => 'Post published',
'body' => $this->post->title,
'url' => "/arrel/admin/posts/{$this->post->id}",
];
}
}| Clave | Uso |
|---|---|
title | Título de la entrada. |
body | Texto opcional bajo el título. |
url | Enlace opcional que se abre al hacer clic en la entrada. |
La campana muestra las 20 últimas notificaciones, el número de las no leídas, y permite marcar una o todas como leídas. Cada usuario solo ve y modifica las suyas.
Siguiente paso
Para decidir quién puede hacer qué dentro del panel, véase Seguridad y autorización.