Cómo utilizar el atributo #[Requires] Atributo

Cuando escribes una aplicación web, a menudo te encuentras con la necesidad de restringir el acceso a ciertas partes de tu aplicación. Tal vez desee que algunas peticiones sólo puedan enviar datos a través de un formulario (utilizando así el método POST) o que sólo sean accesibles para llamadas AJAX. En Nette Framework 3.2, se ha introducido una nueva herramienta que permite establecer estas restricciones de forma elegante y clara: el atributo #[Requires] atributo.

El atributo es un marcador especial en PHP, que se añade antes de la definición de una clase o método. Dado que se trata esencialmente de una clase, es necesario incluir la cláusula use para que los siguientes ejemplos funcionen:

use Nette\Application\Attributes\Requires;

Puede utilizar el atributo #[Requires] con la propia clase presentadora y en estos métodos:

  • action<Action>()
  • render<View>()
  • handle<Signal>()
  • createComponent<Name>()

Los dos últimos métodos también afectan a los componentes, por lo que también puede utilizar el atributo con ellos.

Si no se cumplen las condiciones especificadas por el atributo, se produce un error HTTP 4×x.

Métodos HTTP

Puede especificar qué métodos HTTP (como GET, POST, etc.) están permitidos para el acceso. Por ejemplo, si desea permitir el acceso sólo mediante el envío de un formulario, establezca:

class AdminPresenter extends Nette\Application\UI\Presenter
{
	#[Requires(methods: 'POST')]
	public function actionDelete(int $id): void
	{
	}
}

¿Por qué debería utilizar POST en lugar de GET para las acciones de cambio de estado y cómo hacerlo? Lea la guía.

Puede especificar un método o un conjunto de métodos. Un caso especial es el valor '*' para habilitar todos los métodos, que los presentadores no permiten por defecto por motivos de seguridad.

Llamadas AJAX

Si desea que un presentador o método sea accesible sólo para peticiones AJAX, utilice:

#[Requires(ajax: true)]
class AjaxPresenter extends Nette\Application\UI\Presenter
{
}

Mismo origen

Para mejorar la seguridad, puede exigir que la solicitud se realice desde el mismo dominio. Esto evita la vulnerabilidad a CSRF:

#[Requires(sameOrigin: true)]
class SecurePresenter extends Nette\Application\UI\Presenter
{
}

Para los métodos handle<Signal>() se requiere automáticamente el acceso desde el mismo dominio. Por lo tanto, si desea permitir el acceso desde cualquier dominio, especifique:

#[Requires(sameOrigin: false)]
public function handleList(): void
{
}

Acceso a través de Forward

A veces es útil restringir el acceso a un presentador para que sólo esté disponible indirectamente, por ejemplo, utilizando los métodos forward() o switch() desde otro presentador. Así es como se protegen los presentadores de errores para evitar que se activen desde una URL:

#[Requires(forward: true)]
class ForwardedPresenter extends Nette\Application\UI\Presenter
{
}

En la práctica, a menudo es necesario marcar determinadas vistas a las que sólo se puede acceder basándose en la lógica del presentador. De nuevo, para que no puedan abrirse 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 específicas

También puede restringir que cierto código, como la creación de un componente, sea accesible sólo para acciones específicas en el presentador:

class EditDeletePresenter extends Nette\Application\UI\Presenter
{
	#[Requires(actions: ['add', 'edit'])]
	public function createComponentPostForm()
	{
	}
}

Para una sola acción, no es necesario escribir una matriz: #[Requires(actions: 'default')]

Atributos personalizados

Si desea utilizar el atributo #[Requires] atributo repetidamente con la misma configuración, puede crear su propio atributo que heredará #[Requires] y configurarlo según tus necesidades.

Por ejemplo #[SingleAction] sólo permite el acceso 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 a través de todos los métodos HTTP utilizados para 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] te ofrece una gran flexibilidad y control sobre cómo se accede a tus páginas web. Usando reglas simples, pero potentes, puedes mejorar la seguridad y el buen funcionamiento de tu aplicación. Como puede ver, el uso de atributos en Nette no sólo puede simplificar su trabajo, sino también asegurarlo.