Comment utiliser l'attribut #[Requires] Attribut

Lorsque vous écrivez une application web, vous rencontrez souvent le besoin de restreindre l'accès à certaines parties de votre application. Vous souhaitez peut-être que certaines requêtes ne puissent envoyer des données que par l'intermédiaire d'un formulaire (en utilisant donc la méthode POST) ou qu'elles ne soient accessibles qu'aux appels AJAX. Dans le Nette Framework 3.2, un nouvel outil a été introduit qui vous permet de définir de telles restrictions de manière élégante et claire : l'attribut #[Requires] attribut.

L'attribut est un marqueur spécial en PHP, que vous ajoutez avant la définition d'une classe ou d'une méthode. Comme il s'agit essentiellement d'une classe, vous devez inclure la clause use pour que les exemples suivants fonctionnent :

use Nette\Application\Attributes\Requires;

Vous pouvez utiliser l'attribut #[Requires] avec la classe du présentateur elle-même et avec ces méthodes :

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

Les deux dernières méthodes concernent également les composants, de sorte que vous pouvez également utiliser l'attribut avec eux.

Si les conditions spécifiées par l'attribut ne sont pas remplies, une erreur HTTP 4×x est déclenchée.

Méthodes HTTP

Vous pouvez spécifier les méthodes HTTP (telles que GET, POST, etc.) autorisées pour l'accès. Par exemple, si vous souhaitez n'autoriser l'accès qu'en soumettant un formulaire, définissez :

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

Pourquoi utiliser POST au lieu de GET pour les actions de changement d'état et comment le faire ? Lire le guide.

Vous pouvez spécifier une méthode ou un tableau de méthodes. Un cas particulier est la valeur '*' qui permet d'activer toutes les méthodes, ce que les présentateurs n'autorisent pas par défaut pour des raisons de sécurité.

Appels AJAX

Si vous souhaitez qu'un présentateur ou une méthode ne soit accessible que pour les requêtes AJAX, utilisez :

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

Même origine

Pour renforcer la sécurité, vous pouvez exiger que la demande soit faite à partir du même domaine. Cela permet d'éviter la vulnérabilité au CSRF:

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

Pour les méthodes handle<Signal>() l'accès à partir du même domaine est automatiquement requis. Par conséquent, si vous souhaitez autoriser l'accès à partir de n'importe quel domaine, indiquez :

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

Accès via Forward

Il est parfois utile de restreindre l'accès à un présentateur pour qu'il ne soit accessible qu'indirectement, par exemple en utilisant les méthodes forward() ou switch() d'un autre présentateur. C'est ainsi que les présentateurs d'erreurs sont protégés pour éviter qu'ils ne soient déclenchés à partir d'une URL :

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

Dans la pratique, il est souvent nécessaire de marquer certaines vues auxquelles on ne peut accéder qu'en fonction de la logique du présentateur. Là encore, elles ne peuvent pas être ouvertes directement :

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
	{
	}
}

Actions spécifiques

Vous pouvez également limiter l'accès à certains codes, comme la création d'un composant, à des actions spécifiques dans le présentateur :

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

Pour une action unique, il n'est pas nécessaire d'écrire un tableau : #[Requires(actions: 'default')]

Attributs personnalisés

Si vous souhaitez utiliser l'attribut #[Requires] à plusieurs reprises avec les mêmes paramètres, vous pouvez créer votre propre attribut qui héritera de l'attribut #[Requires] et le paramétrer en fonction de vos besoins.

Par exemple, l'attribut #[SingleAction] n'autorise l'accès que par l'action default:

#[Attribute]
class SingleAction extends Nette\Application\Attributes\Requires
{
	public function __construct()
	{
		parent::__construct(actions: 'default');
	}
}

#[SingleAction]
class SingleActionPresenter extends Nette\Application\UI\Presenter
{
}

ou #[RestMethods] permet l'accès via toutes les méthodes HTTP utilisées pour l'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
{
}

Conclusion

L'attribut #[Requires] vous offre une grande flexibilité et un contrôle sur la manière dont vos pages web sont accessibles. En utilisant des règles simples mais puissantes, vous pouvez améliorer la sécurité et le bon fonctionnement de votre application. Comme vous pouvez le constater, l'utilisation des attributs dans Nette peut non seulement simplifier votre travail, mais aussi le sécuriser.