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 4xx 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.