Come utilizzare l'attributo #[Requires]
Attributo
Quando si scrive un'applicazione web, spesso si incontra la necessità di limitare l'accesso a certe parti
dell'applicazione. Forse si desidera che alcune richieste possano essere inviate solo tramite un modulo (utilizzando quindi il
metodo POST) o che siano accessibili solo alle chiamate AJAX. In Nette Framework 3.2 è stato introdotto un nuovo strumento che
consente di impostare tali restrizioni in modo elegante e chiaro: l'attributo #[Requires]
attributo.
L'attributo è un marcatore speciale in PHP, che si aggiunge prima della definizione di una classe o di un metodo. Poiché si tratta essenzialmente di una classe, è necessario includere la clausola use per far funzionare gli esempi seguenti:
use Nette\Application\Attributes\Requires;
È possibile utilizzare l'attributo #[Requires]
con la classe del presentatore e con questi metodi:
action<Action>()
render<View>()
handle<Signal>()
createComponent<Name>()
Anche gli ultimi due metodi riguardano i componenti, quindi è possibile utilizzare l'attributo anche con essi.
Se le condizioni specificate dall'attributo non sono soddisfatte, viene generato un errore HTTP 4xx.
Metodi HTTP
È possibile specificare quali metodi HTTP (come GET, POST, ecc.) sono consentiti per l'accesso. Ad esempio, se si desidera consentire l'accesso solo tramite l'invio di un modulo, impostare:
class AdminPresenter extends Nette\Application\UI\Presenter
{
#[Requires(methods: 'POST')]
public function actionDelete(int $id): void
{
}
}
Perché usare POST invece di GET per le azioni di modifica dello stato e come farlo? Leggete la guida.
È possibile specificare un metodo o una serie di metodi. Un caso particolare è il valore '*'
per abilitare
tutti i metodi, che i presentatori non consentono di default per motivi di sicurezza.
Chiamate AJAX
Se si desidera che un presentatore o un metodo sia accessibile solo per le richieste AJAX, utilizzare:
#[Requires(ajax: true)]
class AjaxPresenter extends Nette\Application\UI\Presenter
{
}
Stessa origine
Per migliorare la sicurezza, è possibile richiedere che la richiesta venga effettuata dallo stesso dominio. In questo modo si evita la vulnerabilità al CSRF:
#[Requires(sameOrigin: true)]
class SecurePresenter extends Nette\Application\UI\Presenter
{
}
Per i metodi handle<Signal>()
l'accesso dallo stesso dominio è automaticamente richiesto. Pertanto, se si
desidera consentire l'accesso da qualsiasi dominio, specificare:
#[Requires(sameOrigin: false)]
public function handleList(): void
{
}
Accesso tramite Forward
A volte è utile limitare l'accesso a un presentatore in modo che sia disponibile solo indirettamente, ad esempio utilizzando
i metodi forward()
o switch()
di un altro presentatore. In questo modo si proteggono i presentatori di
errori, per evitare che vengano attivati da un URL:
#[Requires(forward: true)]
class ForwardedPresenter extends Nette\Application\UI\Presenter
{
}
In pratica, spesso è necessario contrassegnare alcune viste a cui si può accedere solo in base alla logica del presentatore. Anche in questo caso, in modo che 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
È anche possibile limitare l'accesso a determinati codici, come la creazione di un componente, solo per azioni specifiche nel presentatore:
class EditDeletePresenter extends Nette\Application\UI\Presenter
{
#[Requires(actions: ['add', 'edit'])]
public function createComponentPostForm()
{
}
}
Per una singola azione, non è necessario scrivere un array: #[Requires(actions: 'default')]
Attributi personalizzati
Se si desidera utilizzare l'attributo #[Requires]
con le stesse impostazioni, è possibile creare un attributo
personalizzato che erediterà #[Requires]
e impostarlo secondo le proprie esigenze.
Ad esempio, #[SingleAction]
consente l'accesso solo attraverso 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 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
{
}
Conclusione
L'attributo #[Requires]
offre grande flessibilità e controllo sulle modalità di accesso alle pagine web.
Utilizzando regole semplici ma potenti, è possibile migliorare la sicurezza e il corretto funzionamento dell'applicazione. Come
si può vedere, l'uso degli attributi in Nette non solo semplifica il lavoro, ma lo rende anche sicuro.