Как использовать #[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()
из другого презентатора. Так защищаются презентаторы
ошибок, чтобы их нельзя было вызвать с URL:
#[Requires(forward: true)]
class ForwardedPresenter extends Nette\Application\UI\Presenter
{
}
На практике часто возникает необходимость пометить определенные представления, доступ к которым возможен только на основе логики в презентере. Опять же, чтобы их нельзя было открыть напрямую:
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 может не только упростить вашу работу, но
и обезопасить ее.