Come usare l'attributo #[Requires]
Quando scrivi un'applicazione web, ti imbatterai spesso nella necessità di limitare l'accesso a determinate
parti della tua applicazione. Forse vuoi che alcune richieste possano inviare dati solo tramite un form (cioè con il metodo
POST), o che siano accessibili solo per chiamate AJAX. In Nette Framework 3.2 è apparso un nuovo strumento che ti permette di
impostare tali limitazioni in modo molto elegante e chiaro: l'attributo #[Requires]
.
L'attributo è un marcatore speciale in PHP che aggiungi prima della definizione di una classe o di un metodo. Poiché si tratta effettivamente di una classe, affinché gli esempi seguenti funzionino, è necessario specificare la clausola use:
use Nette\Application\Attributes\Requires;
L'attributo #[Requires]
può essere utilizzato sulla classe stessa del presenter e anche su questi metodi:
action<Action>()
render<View>()
handle<Signal>()
createComponent<Name>()
Gli ultimi due metodi riguardano anche i componenti, quindi puoi usare l'attributo anche su di essi.
Se le condizioni specificate dall'attributo non sono soddisfatte, verrà generato un errore HTTP 4xx.
Metodi HTTP
Puoi specificare quali metodi HTTP (come GET, POST, ecc.) sono consentiti per l'accesso. Ad esempio, se vuoi consentire l'accesso solo inviando un form, imposta:
class AdminPresenter extends Nette\Application\UI\Presenter
{
#[Requires(methods: 'POST')]
public function actionDelete(int $id): void
{
}
}
Perché dovresti usare POST invece di GET per azioni che modificano lo stato e come farlo? Leggi la guida.
Puoi specificare un metodo o un array di metodi. Un caso speciale è il valore '*'
, che consente tutti i metodi,
cosa che i presenter standard non
permettono per motivi di sicurezza.
Chiamata AJAX
Se vuoi che il presenter o il metodo sia disponibile solo per le richieste AJAX, usa:
#[Requires(ajax: true)]
class AjaxPresenter extends Nette\Application\UI\Presenter
{
}
Stessa origine
Per aumentare la sicurezza, puoi richiedere che la richiesta sia effettuata dallo stesso dominio. Ciò previene la vulnerabilità CSRF:
#[Requires(sameOrigin: true)]
class SecurePresenter extends Nette\Application\UI\Presenter
{
}
Per i metodi handle<Signal>()
, l'accesso dallo stesso dominio è richiesto automaticamente. Quindi, se al
contrario vuoi consentire l'accesso da qualsiasi dominio, specifica:
#[Requires(sameOrigin: false)]
public function handleList(): void
{
}
Accesso tramite forward
A volte è utile limitare l'accesso a un presenter in modo che sia disponibile solo indirettamente, ad esempio utilizzando il
metodo forward()
o switch()
da un altro presenter. In questo modo si proteggono, ad esempio, gli
error-presenter, affinché non possano essere invocati dall'URL:
#[Requires(forward: true)]
class ForwardedPresenter extends Nette\Application\UI\Presenter
{
}
In pratica, è spesso necessario contrassegnare determinate view, alle quali si può accedere solo in base alla logica nel presenter. Cioè, di nuovo, affinché non possano essere aperte direttamente:
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
{
}
}
Azioni specifiche
Puoi anche limitare che un certo codice, ad esempio la creazione di un componente, sia disponibile solo per azioni specifiche nel presenter:
class EditDeletePresenter extends Nette\Application\UI\Presenter
{
#[Requires(actions: ['add', 'edit'])]
public function createComponentPostForm()
{
}
}
Nel caso di una singola azione, non è necessario scrivere un array: #[Requires(actions: 'default')]
Attributi personalizzati
Se vuoi usare l'attributo #[Requires]
ripetutamente con le stesse impostazioni, puoi creare un tuo attributo
personalizzato che erediterà #[Requires]
e lo imposterà secondo le tue esigenze.
Ad esempio, #[SingleAction]
consentirà l'accesso solo tramite l'azione default
:
#[\Attribute]
class SingleAction extends Nette\Application\Attributes\Requires
{
public function __construct()
{
parent::__construct(actions: 'default');
}
}
#[SingleAction]
class SingleActionPresenter extends Nette\Application\UI\Presenter
{
}
Oppure #[RestMethods]
consentirà l'accesso tramite tutti i metodi HTTP utilizzati per le 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
{
}
Conclusione
L'attributo #[Requires]
ti offre grande flessibilità e controllo su come sono accessibili le tue pagine web.
Utilizzando regole semplici ma potenti, puoi aumentare la sicurezza e il corretto funzionamento della tua applicazione. Come vedi,
l'uso degli attributi in Nette può non solo facilitare il tuo lavoro, ma anche renderlo più sicuro.