Cómo usar el atributo #[Requires]
Al escribir una aplicación web se encuentra a menudo con la necesidad de restringir el acceso a ciertas partes
de la aplicación. Quizá quiera que algunas peticiones solo puedan enviar datos mediante un formulario (es decir, usando el
método POST) o que solo sean accesibles para llamadas AJAX. En Nette Framework 3.2 se ha introducido una nueva herramienta que
le permite establecer esas restricciones de forma elegante y clara: el atributo #[Requires].
Un atributo es un marcador especial de PHP que se añade antes de la definición de una clase o de un método. Como en el
fondo es una clase, hay que incluir la cláusula use para que los siguientes ejemplos funcionen:
use Nette\Application\Attributes\Requires;
El atributo #[Requires] se puede usar con la propia clase del presenter y con estos métodos:
action<Action>()render<View>()handle<Signal>()createComponent<Name>()
Los dos últimos métodos afectan también a los componentes, así que puede usar el atributo con ellos igualmente.
Si no se cumplen las condiciones indicadas por el atributo, se lanza un error HTTP 4xx.
Métodos HTTP
Puede indicar qué métodos HTTP (como GET, POST, etc.) están permitidos para el acceso. Por ejemplo, si quiere permitir el acceso solo mediante el envío de un formulario, ponga:
class AdminPresenter extends Nette\Application\UI\Presenter
{
#[Requires(methods: 'POST')]
public function actionDelete(int $id): void
{
}
}
¿Por qué debería usar POST en lugar de GET para las acciones que cambian el estado y cómo hacerlo? Lea la guía.
Puede indicar un método o un array de métodos. Un caso especial es el valor '*', que permite todos los
métodos, algo que los presenters no
permiten de forma predeterminada por motivos de seguridad.
Llamadas AJAX
Si quiere que un presenter o un método sea accesible solo para peticiones AJAX, use:
#[Requires(ajax: true)]
class AjaxPresenter extends Nette\Application\UI\Presenter
{
}
Mismo origen
Para aumentar la seguridad puede exigir que la petición se haga desde el mismo dominio. Eso evita la vulnerabilidad CSRF:
#[Requires(sameOrigin: true)]
class SecurePresenter extends Nette\Application\UI\Presenter
{
}
Para los métodos handle<Signal>(), el acceso desde el mismo dominio se exige automáticamente. Así que, si
quiere permitir el acceso desde cualquier dominio, indique:
#[Requires(sameOrigin: false)]
public function handleList(): void
{
}
Acceso mediante forward
A veces resulta útil restringir el acceso a un presenter de modo que solo esté disponible indirectamente, por ejemplo con
los métodos forward() o switch() desde otro presenter. Así se protegen, por ejemplo, los presenters de
error, para que no se puedan invocar desde una URL:
#[Requires(forward: true)]
class ForwardedPresenter extends Nette\Application\UI\Presenter
{
}
En la práctica es frecuente que haga falta marcar ciertas vistas a las que solo se puede llegar en función de la lógica del presenter. De nuevo, para que no se puedan abrir directamente:
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function actionDefault(int $id): void
{
$product = $this->facade->getProduct($id);
if (!$product) {
$this->setView('notfound');
}
}
#[Requires(forward: true)]
public function renderNotFound(): void
{
}
}
Acciones concretas
También puede restringir cierto código, como la creación de un componente, para que solo sea accesible en acciones concretas del presenter:
class EditDeletePresenter extends Nette\Application\UI\Presenter
{
#[Requires(actions: ['add', 'edit'])]
public function createComponentPostForm()
{
}
}
En el caso de una sola acción no hace falta escribir un array: #[Requires(actions: 'default')]
Atributos propios
Si quiere usar el atributo #[Requires] repetidamente con la misma configuración, puede crear su propio atributo
que herede de #[Requires] y lo configure según sus necesidades.
Por ejemplo, #[SingleAction] permite el acceso solo a través de la acción default:
#[\Attribute]
class SingleAction extends Nette\Application\Attributes\Requires
{
public function __construct()
{
parent::__construct(actions: 'default');
}
}
#[SingleAction]
class SingleActionPresenter extends Nette\Application\UI\Presenter
{
}
O #[RestMethods] permitirá el acceso mediante todos los métodos HTTP usados por la API REST:
#[\Attribute]
class RestMethods extends Nette\Application\Attributes\Requires
{
public function __construct()
{
parent::__construct(methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
}
}
#[RestMethods]
class ApiPresenter extends Nette\Application\UI\Presenter
{
}
Conclusión
El atributo #[Requires] le da una gran flexibilidad y control sobre cómo se accede a sus páginas web. Con reglas
sencillas pero potentes puede reforzar la seguridad y el correcto funcionamiento de su aplicación. Como ve, usar atributos en
Nette no solo puede simplificarle el trabajo, sino también hacerlo más seguro.