Cum se utilizează atributul #[Requires]

Când scrieți o aplicație web, adesea vă confruntați cu nevoia de a restricționa accesul la anumite părți ale aplicației dvs. Poate doriți ca unele cereri să poată trimite date doar folosind un formular (adică prin metoda POST), sau să fie accesibile doar pentru apeluri AJAX. În Nette Framework 3.2 a apărut un nou instrument care vă permite să setați astfel de restricții foarte elegant și clar: atributul #[Requires].

Atributul este o marcă specială în PHP, pe care o adăugați înaintea definiției unei clase sau metode. Deoarece este de fapt o clasă, pentru ca următoarele exemple să funcționeze, este necesar să specificați clauza use:

use Nette\Application\Attributes\Requires;

Atributul #[Requires] îl puteți utiliza la clasa presenterului însuși și, de asemenea, la aceste metode:

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

Ultimele două metode se referă și la componente, deci atributul îl puteți utiliza și la ele.

Dacă nu sunt îndeplinite condițiile specificate de atribut, se va declanșa o eroare HTTP 4xx.

Metode HTTP

Puteți specifica ce metode HTTP (cum ar fi GET, POST etc.) sunt permise pentru acces. De exemplu, dacă doriți să permiteți accesul doar prin trimiterea unui formular, setați:

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

De ce ar trebui să utilizați POST în loc de GET pentru acțiunile care modifică starea și cum să faceți asta? Citiți ghidul.

Puteți specifica o metodă sau un array de metode. Un caz special este valoarea '*', care permite toate metodele, ceea ce presenterele standard nu permit din motive de securitate.

Apel AJAX

Dacă doriți ca presenterul sau metoda să fie disponibilă doar pentru cereri AJAX, utilizați:

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

Aceeași origine

Pentru a crește securitatea, puteți solicita ca cererea să fie făcută din același domeniu. Astfel preveniți vulnerabilitatea CSRF:

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

Pentru metodele handle<Signal>(), accesul din același domeniu este solicitat automat. Deci, dacă, dimpotrivă, doriți să permiteți accesul din orice domeniu, specificați:

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

Acces prin forward

Uneori este util să restricționați accesul la presenter astfel încât să fie disponibil doar indirect, de exemplu folosind metoda forward() sau switch() dintr-un alt presenter. Astfel se protejează, de exemplu, error-presenterele, pentru a nu putea fi apelate din URL:

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

În practică, este adesea necesar să se marcheze anumite view-uri, la care se poate ajunge doar pe baza logicii din presenter. Adică, din nou, pentru a nu putea fi deschise direct:

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

Acțiuni specifice

Puteți, de asemenea, să restricționați ca un anumit cod, de exemplu crearea unei componente, să fie disponibil doar pentru acțiuni specifice în presenter:

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

În cazul unei singure acțiuni, nu este necesar să scrieți un array: #[Requires(actions: 'default')]

Atribute personalizate

Dacă doriți să utilizați atributul #[Requires] în mod repetat cu aceleași setări, puteți crea propriul atribut, care va moșteni #[Requires] și îl va seta conform nevoilor.

De exemplu, #[SingleAction] va permite accesul doar prin acțiunea default:

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

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

Sau #[RestMethods] va permite accesul prin toate metodele HTTP utilizate pentru API-uri 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
{
}

Concluzie

Atributul #[Requires] vă oferă o mare flexibilitate și control asupra modului în care paginile dvs. web sunt accesibile. Folosind reguli simple, dar puternice, puteți crește securitatea și funcționarea corectă a aplicației dvs. După cum vedeți, utilizarea atributelor în Nette vă poate nu numai ușura munca, ci și securiza.