Ce qui se passe
Quand #[IsSignatureValid] échouait sur un lien expiré, l'utilisateur recevait une réponse d'erreur.
Pour afficher un message et rediriger, il fallait retirer l'attribut et refaire le contrôle soi-même.
Symfony 8.2 (contribution de Kevin Bond, #67563) injecte désormais l'exception dans un argument nullable du contrôleur, s'il en déclare un :
| Attribut | Exception |
|---|---|
#[IsCsrfTokenValid] |
InvalidCsrfTokenException |
#[IsSignatureValid] |
SignedUriException |
#[Lock] |
LockConflictedException |
#[RateLimit] |
RateLimitExceededException |
Comment s'y prendre
Le type de l'argument décide de ce que vous traitez : une sous-classe comme ExpiredSignedUriException
restreint le cas, un type union en couvre plusieurs. Cet exemple est écrit pour la fiche à partir de la
règle annoncée, sans reprendre celui du billet, et n'a pas été exécuté :
#[IsSignatureValid]
public function confirmer(?ExpiredSignedUriException $expire = null): Response
{
if ($expire) {
return $this->redirectToRoute('renvoyer_lien');
}
// Lien valide : suite normale.
}#[RecoverableAttribute] donne le même comportement à vos propres attributs.
Le piège
Le contrôleur s'exécute même si le contrôle a échoué. Sans test de l'argument, l'action part sans
protection. C'est pourquoi #[IsGranted] n'en profite pas. Rien de tel n'empêche d'oublier le test
pour un jeton CSRF : placez-le en première ligne et couvrez ce chemin par un test.
Source : Symfony, 30 octobre 2026. Source en anglais.