Seguridad y autorización
Arrel decide el acceso en el servidor, en cada endpoint. El frontend oculta los botones que no puedes usar, pero eso es comodidad: la protección real es que la API los rechaza.
Capas de una petición
Una petición a la API de un Resource pasa, en este orden, por:
- El middleware de
config('arrel.middleware')(por ejemplo, identificar el tenant). - La sesión de Sanctum (
auth:sanctum). - La verificación del correo y el segundo factor, si están activados (véase Autenticación).
- El middleware de
config('arrel.authenticated_middleware'). - La autorización del Resource, de la página o de la acción.
Resources
Los cinco métodos canViewAny(), canView(), canCreate(), canEdit() y canDelete() delegan en la Policy del modelo, o se pueden sobrescribir (véase Resources).
Un Resource para el que canViewAny() es falso queda cerrado en todos los endpoints: el listado, pero también el esquema, la creación, la edición, el borrado, las acciones, las opciones de los campos y las relaciones responden 403. Sin esta regla, un modelo sin Policy dejaría canCreate() o canEdit() abiertos de manera independiente.
Esto quiere decir que, para un modelo sin Policy, todo queda permitido para cualquier usuario autenticado. Si el Resource debe ser restringido, define una Policy o sobrescribe canViewAny().
Acciones
- Una acción con
authorize()usa esa closure, con los mismos argumentos quehandle(). - Una acción sin
authorize()exigecanEdit()sobre el registro, ocanCreate()si esstandalone(). Declaraauthorize()en las acciones que deben quedar abiertas a más usuarios. - Las acciones incluidas siguen su habilidad:
ViewActionpidecanView(),EditActionyRestoreActionpidencanEdit(),DeleteActionyForceDeleteActionpidencanDelete(). - Las opciones que una acción ofrece a sus campos de relación solo se sirven a los usuarios que pueden ejecutarla.
Relaciones
Si un campo Relation declara query(), el alcance también se aplica al guardar: un registro que el alcance oculta del desplegable es rechazado con un error de validación, aunque alguien envíe su identificador a mano. Pasa igual en los formularios de un Resource, de un Relation manager y de una acción.
Relation::make('author_id')
->related(User::class)
->query(fn (Builder $query): Builder => $query->where('team_id', auth()->user()->team_id))En la closure de query() de un campo de un Relation manager o de una acción, el registro padre llega como tercer argumento.
Subidas de archivos
- Las subidas están limitadas a 60 por minuto y usuario.
- Al guardar un registro, solo se mueven los archivos que realmente se han subido al directorio temporal (
arrel-temp). Un valor que no corresponde a una subida real no se mueve. - El contenido de los campos
RichEditorse sanitiza en el servidor en cada guardado.
Límites de intentos
| Qué | Límite |
|---|---|
| Inicio de sesión | 5 intentos fallidos por correo y dirección IP |
| Segundo factor de un inicio de sesión pendiente | 5 códigos incorrectos, y caduca a los 5 minutos |
| Envío del correo de verificación | 3 por minuto |
| Confirmar o desactivar el segundo factor | 10 por minuto |
| Subidas de archivos | 60 por minuto y usuario |
Páginas
Page::canView() decide si una página es visible y accesible. Una página que no se puede ver sale de la navegación y responde 403 en la API. Para una CustomPage, visible() controla la entrada de navegación; la autorización de los datos que la página carga debes hacerla en los endpoints de tu aplicación, que son código tuyo.
Lista de comprobación
- Cada modelo expuesto tiene una Policy, o el Resource sobrescribe los
can...(). - Las acciones que no deben ser solo para editores declaran
authorize(). - Los campos
Relationque muestran registros ajenos tienenquery(). sanctum.statefulcontiene solo los dominios de tu panel.- El segundo factor es obligatorio (
isRequiredFor()) para los roles con más privilegios.