Comment utiliser correctement les liens POST

Dans les applications web, en particulier dans les interfaces administratives, la règle de base devrait être que les actions modifiant l'état du serveur ne doivent pas être effectuées via la méthode HTTP GET. Comme le nom de la méthode le suggère, GET ne doit être utilisé que pour récupérer des données, et non pour les modifier. Pour des actions telles que la suppression d'enregistrements, il est plus approprié d'utiliser la méthode POST. L'idéal serait d'utiliser la méthode DELETE, mais celle-ci ne peut être invoquée sans JavaScript, d'où l'utilisation historique de POST.

Comment faire en pratique ? Utilisez cette astuce simple. Au début de votre modèle, créez un formulaire d'aide avec l'identifiant postForm, que vous utiliserez ensuite pour les boutons de suppression :

<form method="post" id="postForm"></form>

Avec ce formulaire, vous pouvez utiliser un <button> au lieu du lien classique <a> qui peut être modifié visuellement pour ressembler à un lien normal. Par exemple, le cadre CSS Bootstrap propose les classes btn btn-link qui permettent au bouton d'être visuellement indiscernable des autres liens. En utilisant l'attribut form="postForm", nous le lions au formulaire préparé à l'avance :

<table>
	<tr n:foreach="$posts as $post">
		<td>{$post->title}</td>
		<td>
			<button class="btn btn-link" form="postForm" formaction="{link delete $post->id}">delete</button>
			<!-- instead of <a n:href="delete $post->id">delete</a> -->
		</td>
	</tr>
</table>

Lorsque l'on clique sur le lien, l'action delete est invoquée. Pour s'assurer que les requêtes ne sont acceptées que par la méthode POST et qu'elles proviennent du même domaine (ce qui constitue une défense efficace contre les attaques CSRF), utilisez l'attribut #[Requires] l'attribut

use Nette\Application\Attributes\Requires;

class AdminPresenter extends Nette\Application\UI\Presenter
{
	#[Requires(methods: 'POST', sameOrigin: true)]
	public function actionDelete(int $id): void
	{
		$this->facade->deletePost($id); // hypothetical code for deleting a record
		$this->redirect('default');
	}
}

L'attribut est disponible depuis Nette Application 3.2, et vous pouvez en apprendre plus sur ses capacités sur la page Comment utiliser l'attribut #Requires.

Si vous utilisez le signal handleDelete() au lieu de l'action actionDelete(), il n'est pas nécessaire de spécifier sameOrigin: true, car les signaux ont cette protection implicite :

#[Requires(methods: 'POST')]
public function handleDelete(int $id): void
{
	$this->facade->deletePost($id);
	$this->redirect('this');
}

Cette approche améliore non seulement la sécurité de votre application, mais contribue également à l'adhésion aux normes et pratiques web appropriées. En utilisant les méthodes POST pour les actions de changement d'état, vous obtenez une application plus robuste et plus sûre.