How to Use the #[Requires]
Attribute
When writing a web application, you often encounter the need to restrict access to certain parts of your
application. Perhaps you want some requests to only be able to send data via a form (thus using the POST method) or to be
accessible only to AJAX calls. In Nette Framework 3.2, a new tool has been introduced that allows you to set such restrictions
elegantly and clearly: the #[Requires]
attribute.
The attribute is a special marker in PHP, which you add before the definition of a class or method. Since it is essentially a class, you need to include the use clause to make the following examples work:
use Nette\Application\Attributes\Requires;
You can use the #[Requires]
attribute with the presenter class itself and on these methods:
action<Action>()
render<View>()
handle<Signal>()
createComponent<Name>()
The last two methods also concern components, so you can use the attribute with them as well.
If the conditions specified by the attribute are not met, an HTTP 4×x error is triggered.
HTTP Methods
You can specify which HTTP methods (such as GET, POST, etc.) are allowed for access. For example, if you want to allow access only by submitting a form, set:
class AdminPresenter extends Nette\Application\UI\Presenter
{
#[Requires(methods: 'POST')]
public function actionDelete(int $id): void
{
}
}
Why should you use POST instead of GET for state changing actions and how to do it? Read the guide.
You can specify a method or an array of methods. A special case is the value '*'
to enable all methods, which
presenters do not allow by default for security
reasons.
AJAX Calls
If you want a presenter or method to be accessible only for AJAX requests, use:
#[Requires(ajax: true)]
class AjaxPresenter extends Nette\Application\UI\Presenter
{
}
Same Origin
To enhance security, you can require that the request be made from the same domain. This prevents vulnerability to CSRF:
#[Requires(sameOrigin: true)]
class SecurePresenter extends Nette\Application\UI\Presenter
{
}
For handle<Signal>()
methods, access from the same domain is automatically required. So, if you want to
allow access from any domain, specify:
#[Requires(sameOrigin: false)]
public function handleList(): void
{
}
Access via Forward
Sometimes it is useful to restrict access to a presenter so that it is only available indirectly, for example, using the
forward()
or switch()
methods from another presenter. This is how error-presenters are protected to
prevent them from being triggered from a URL:
#[Requires(forward: true)]
class ForwardedPresenter extends Nette\Application\UI\Presenter
{
}
In practice, it is often necessary to mark certain views that can only be accessed based on logic in the presenter. Again, so that they cannot be opened directly:
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
{
}
}
Specific Actions
You can also restrict that certain code, like creating a component, will be accessible only for specific actions in the presenter:
class EditDeletePresenter extends Nette\Application\UI\Presenter
{
#[Requires(actions: ['add', 'edit'])]
public function createComponentPostForm()
{
}
}
For a single action, there's no need to write an array: #[Requires(actions: 'default')]
Custom Attributes
If you want to use the #[Requires]
attribute repeatedly with the same settings, you can create your own attribute
that will inherit #[Requires]
and set it according to your needs.
For example, #[SingleAction]
allows access only through the default
action:
#[Attribute]
class SingleAction extends Nette\Application\Attributes\Requires
{
public function __construct()
{
parent::__construct(actions: 'default');
}
}
#[SingleAction]
class SingleActionPresenter extends Nette\Application\UI\Presenter
{
}
Or #[RestMethods]
will allow access via all HTTP methods used for the 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
{
}
Conclusion
The #[Requires]
attribute gives you great flexibility and control over how your web pages are accessed. Using
simple, yet powerful rules, you can enhance the security and proper functioning of your application. As you can see, using
attributes in Nette can not only simplify your work but also secure it.