Hogyan használjuk a #[Requires] attribútumot

Amikor webalkalmazást ír, gyakran találkozik azzal az igénnyel, hogy korlátozza a hozzáférést az alkalmazás bizonyos részeihez. Talán azt szeretné, hogy bizonyos kérések csak űrlapon keresztül küldhessenek adatokat (azaz POST metódussal), vagy hogy csak AJAX hívások számára legyenek elérhetők. A Nette Framework 3.2-ben megjelent egy új eszköz, amely lehetővé teszi az ilyen korlátozások nagyon elegáns és áttekinthető beállítását: a #[Requires] attribútum.

Az attribútum egy speciális jelölés a PHP-ban, amelyet az osztály vagy metódus definíciója elé adunk hozzá. Mivel valójában egy osztályról van szó, ahhoz, hogy a következő példák működjenek, meg kell adni a use klauzult:

use Nette\Application\Attributes\Requires;

A #[Requires] attribútumot használhatja magánál a presenter osztálynál és ezeknél a metódusoknál is:

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

Az utolsó két metódus a komponensekre is vonatkozik, tehát az attribútumot náluk is használhatja.

Ha az attribútum által megadott feltételek nem teljesülnek, HTTP 4xx hiba váltódik ki.

HTTP metódusok

Megadhatja, hogy mely HTTP metódusok (mint GET, POST stb.) engedélyezettek a hozzáféréshez. Például, ha csak űrlapküldéssel szeretné engedélyezni a hozzáférést, állítsa be:

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

Miért kellene POST-ot használnia GET helyett az állapotot megváltoztató akciókhoz, és hogyan tegye ezt? Olvassa el az útmutatót.

Megadhat egy metódust vagy metódusok tömbjét. Speciális eset a '*' érték, amely minden metódust engedélyez, amit a presenterek biztonsági okokból alapértelmezés szerint nem engednek meg.

AJAX hívás

Ha azt szeretné, hogy a presenter vagy metódus csak AJAX kérések számára legyen elérhető, használja:

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

Azonos eredet

A biztonság növelése érdekében megkövetelheti, hogy a kérés ugyanarról a domainről érkezzen. Ezzel megakadályozhatja a CSRF sebezhetőséget:

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

A handle<Signal>() metódusoknál az azonos domainről való hozzáférés automatikusan megkövetelt. Tehát ha fordítva, bármely domainről szeretné engedélyezni a hozzáférést, adja meg:

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

Hozzáférés forwardon keresztül

Néha hasznos korlátozni a presenterhez való hozzáférést úgy, hogy csak közvetve legyen elérhető, például a forward() vagy switch() metódus használatával egy másik presenterből. Így védik például az error-presentereket, hogy ne lehessen őket URL-ből meghívni:

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

A gyakorlatban gyakran szükség van bizonyos view-k megjelölésére, amelyekhez csak a presenter logikája alapján lehet eljutni. Tehát ismét, hogy ne lehessen őket közvetlenül megnyitni:

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

Konkrét akciók

Korlátozhatja azt is, hogy egy bizonyos kód, például egy komponens létrehozása, csak specifikus akciókhoz legyen elérhető a presenterben:

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

Egyetlen akció esetén nem szükséges tömböt írni: #[Requires(actions: 'default')]

Saját attribútumok

Ha a #[Requires] attribútumot ismételten ugyanazzal a beállítással szeretné használni, létrehozhat saját attribútumot, amely örökli a #[Requires]-t, és az igényeknek megfelelően állítja be.

Például a #[SingleAction] csak a default akción keresztül engedélyezi a hozzáférést:

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

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

Vagy a #[RestMethods] engedélyezi a hozzáférést az összes REST API-hoz használt HTTP metóduson keresztül:

#[\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
{
}

Következtetés

A #[Requires] attribútum nagy rugalmasságot és kontrollt ad Önnek afölött, hogyan érhetők el a weboldalai. Egyszerű, de erőteljes szabályok segítségével növelheti alkalmazása biztonságát és helyes működését. Mint láthatja, az attribútumok használata a Nette-ben nemcsak megkönnyítheti a munkáját, hanem biztonságosabbá is teheti.