Как да използваме атрибута #[Requires]
Когато пишете уеб приложение, често се сблъсквате с
необходимостта да ограничите достъпа до определени части от вашето
приложение. Може би искате някои заявки да могат да изпращат данни само
чрез формуляр (т.е. с метод POST), или да бъдат достъпни само за AJAX
извиквания. В Nette Framework 3.2 се появи нов инструмент, който ви позволява да
настроите такива ограничения много елегантно и прегледно: атрибутът
#[Requires]
.
Атрибутът е специална маркировка в PHP, която добавяте преди дефиницията на клас или метод. Тъй като всъщност е клас, за да работят следващите примери, е необходимо да се посочи клаузата use:
use Nette\Application\Attributes\Requires;
Атрибутът #[Requires]
можете да използвате при самия клас на
презентера, както и на тези методи:
action<Action>()
render<View>()
handle<Signal>()
createComponent<Name>()
Последните два метода се отнасят и до компоненти, т.е. атрибутът можете да използвате и при тях.
Ако не са изпълнени условията, които атрибутът посочва, ще се предизвика HTTP грешка 4xx.
Методи HTTP
Можете да специфицирате кои HTTP методи (като GET, POST и т.н.) са разрешени за достъп. Например, ако искате да разрешите достъп само чрез изпращане на формуляр, настройте:
class AdminPresenter extends Nette\Application\UI\Presenter
{
#[Requires(methods: 'POST')]
public function actionDelete(int $id): void
{
}
}
Защо трябва да използвате POST вместо GET за действия, променящи състоянието, и как да го направите? Прочетете ръководството.
Можете да посочите метод или масив от методи. Специален случай е
стойността '*'
, която разрешава всички методи, което стандартно
презентерите от
съображения за сигурност не позволяват.
AJAX извикване
Ако искате презентерът или методът да бъдат достъпни само за AJAX заявки, използвайте:
#[Requires(ajax: true)]
class AjaxPresenter extends Nette\Application\UI\Presenter
{
}
Същият произход
За повишаване на сигурността можете да изисквате заявката да бъде направена от същия домейн. С това предотвратявате уязвимостта CSRF:
#[Requires(sameOrigin: true)]
class SecurePresenter extends Nette\Application\UI\Presenter
{
}
При методите handle<Signal>()
достъпът от същия домейн се изисква
автоматично. Така че, ако обратно искате да разрешите достъп от всеки
домейн, посочете:
#[Requires(sameOrigin: false)]
public function handleList(): void
{
}
Достъп чрез forward
Понякога е полезно да се ограничи достъпът до презентера така, че да
бъде достъпен само непряко, например с използването на метода
forward()
или switch()
от друг презентер. Така например се
защитават error-presenter-ите, за да не могат да бъдат извикани от URL:
#[Requires(forward: true)]
class ForwardedPresenter extends Nette\Application\UI\Presenter
{
}
На практика често е необходимо да се маркират определени views, до които може да се стигне едва въз основа на логиката в презентера. Тоест отново, за да не могат да бъдат отворени директно:
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
{
}
}
Конкретни действия
Можете също така да ограничите, че определен код, например създаване на компонент, ще бъде достъпен само за специфични действия в презентера:
class EditDeletePresenter extends Nette\Application\UI\Presenter
{
#[Requires(actions: ['add', 'edit'])]
public function createComponentPostForm()
{
}
}
В случай на едно действие не е необходимо да се записва
масив: #[Requires(actions: 'default')]
Собствени атрибути
Ако искате да използвате атрибута #[Requires]
многократно със
същите настройки, можете да си създадете собствен атрибут, който ще
наследява #[Requires]
и ще го настрои според нуждите.
Например #[SingleAction]
ще позволи достъп само чрез действието
default
:
#[\Attribute]
class SingleAction extends Nette\Application\Attributes\Requires
{
public function __construct()
{
parent::__construct(actions: 'default');
}
}
#[SingleAction]
class SingleActionPresenter extends Nette\Application\UI\Presenter
{
}
Или #[RestMethods]
ще позволи достъп чрез всички HTTP методи,
използвани за REST API:
#[\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
{
}
Заключение
Атрибутът #[Requires]
ви дава голяма гъвкавост и контрол върху това
как са достъпни вашите уеб страници. С помощта на прости, но мощни
правила можете да повишите сигурността и правилното функциониране на
вашето приложение. Както виждате, използването на атрибути в Nette може
не само да улесни вашата работа, но и да я обезопаси.