Nette Documentation Preview

syntax
Как да използваме атрибута `#[Requires]`
****************************************

.[perex]
Когато пишете уеб приложение, често се сблъсквате с необходимостта да ограничите достъпа до определени части от вашето приложение. Може би искате някои заявки да могат да изпращат данни само чрез формуляр (т.е. с метод POST), или да бъдат достъпни само за AJAX извиквания. В Nette Framework 3.2 се появи нов инструмент, който ви позволява да настроите такива ограничения много елегантно и прегледно: атрибутът `#[Requires]`.

Атрибутът е специална маркировка в PHP, която добавяте преди дефиницията на клас или метод. Тъй като всъщност е клас, за да работят следващите примери, е необходимо да се посочи клаузата use:

```php
use Nette\Application\Attributes\Requires;
```

Атрибутът `#[Requires]` можете да използвате при самия клас на презентера, както и на тези методи:

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

Последните два метода се отнасят и до компоненти, т.е. атрибутът можете да използвате и при тях.

Ако не са изпълнени условията, които атрибутът посочва, ще се предизвика HTTP грешка 4xx.


Методи HTTP
-----------

Можете да специфицирате кои HTTP методи (като GET, POST и т.н.) са разрешени за достъп. Например, ако искате да разрешите достъп само чрез изпращане на формуляр, настройте:

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

Защо трябва да използвате POST вместо GET за действия, променящи състоянието, и как да го направите? [Прочетете ръководството |post-links].

Можете да посочите метод или масив от методи. Специален случай е стойността `'*'`, която разрешава всички методи, което стандартно презентерите [от съображения за сигурност не позволяват |application:presenters#Проверка на HTTP метода].


AJAX извикване
--------------

Ако искате презентерът или методът да бъдат достъпни само за AJAX заявки, използвайте:

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


Същият произход
---------------

За повишаване на сигурността можете да изисквате заявката да бъде направена от същия домейн. С това предотвратявате [уязвимостта CSRF |nette:vulnerability-protection#Cross-Site Request Forgery CSRF]:

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

При методите `handle<Signal>()` достъпът от същия домейн се изисква автоматично. Така че, ако обратно искате да разрешите достъп от всеки домейн, посочете:

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


Достъп чрез forward
-------------------

Понякога е полезно да се ограничи достъпът до презентера така, че да бъде достъпен само непряко, например с използването на метода `forward()` или `switch()` от друг презентер. Така например се защитават error-presenter-ите, за да не могат да бъдат извикани от URL:

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

На практика често е необходимо да се маркират определени views, до които може да се стигне едва въз основа на логиката в презентера. Тоест отново, за да не могат да бъдат отворени директно:

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


Конкретни действия
------------------

Можете също така да ограничите, че определен код, например създаване на компонент, ще бъде достъпен само за специфични действия в презентера:

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

В случай на едно действие не е необходимо да се записва масив: `#[Requires(actions: 'default')]`


Собствени атрибути
------------------

Ако искате да използвате атрибута `#[Requires]` многократно със същите настройки, можете да си създадете собствен атрибут, който ще наследява `#[Requires]` и ще го настрои според нуждите.

Например `#[SingleAction]` ще позволи достъп само чрез действието `default`:

```php
#[\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:

```php
#[\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 може не само да улесни вашата работа, но и да я обезопаси.

{{sitename: Best Practices}}

Как да използваме атрибута #[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 може не само да улесни вашата работа, но и да я обезопаси.