Access Control (Authorization)

Authorization checks whether a user has sufficient permissions, for example, to access a specific resource or to perform an action. Authorization presupposes prior successful authentication, i.e., that the user is logged in.

→ Installation and requirements

In the examples, we will use an object of the class Nette\Security\User, which represents the current user and which you get by having it passed to you using dependency injection. In presenters, just call $user = $this->getUser().

For very simple websites with administration where user permissions are not differentiated, the already known method isLoggedIn() can be used as the authorization criterion. In other words: as soon as a user is logged in, they have all permissions, and vice versa.

if ($user->isLoggedIn()) { // is the user logged in?
	deleteItem(); // then they have permission for the operation
}

Roles

The purpose of roles is to offer more precise control over permissions and remain independent of the username. As soon as a user logs in, they are assigned one or more roles in which they will act. Roles can be simple strings, for example, admin, member, guest, etc. They are specified as the second argument of the SimpleIdentity constructor, either as a string or an array of strings – roles.

As an authorization criterion, we will now use the isInRole() method, which reveals whether the user is acting in the given role:

if ($user->isInRole('admin')) { // is the user in the admin role?
	deleteItem(); // then they have permission for the operation
}

As you already know, logging out the user does not have to delete their identity. Thus, the getIdentity() method still returns the SimpleIdentity object, including all granted roles. Nette Framework espouses the principle “less code, more security,” where less writing leads to more secure code. Therefore, when checking roles, you do not need to verify whether the user is logged in. The isInRole() method works with effective roles: if the user is logged in, it is based on the roles specified in the identity; if not logged in, they automatically have the special role guest (or the roles of the guest identity, if one is provided).

Authorizer

In addition to roles, we will introduce the terms resource and operation:

  • role is a property of the user – e.g., moderator, editor, visitor, registered user, administrator…
  • resource is a logical unit of the website – article, page, user, menu item, poll, presenter, …
  • operation is a specific activity that the user can or cannot perform with the resource – e.g., view, edit, delete, vote, …

An authorizer is an object that decides whether the given role has permission to perform a certain operation with a specific resource. It is an object implementing the Nette\Security\Authorizator interface with a single method isAllowed():

class MyAuthorizator implements Nette\Security\Authorizator
{
	public function isAllowed($role, $resource, $operation): bool
	{
		if ($role === 'admin') {
			return true;
		}
		if ($role === 'user' && $resource === 'article') {
			return true;
		}

		// ...

		return false;
	}
}

We add the authorizer to the configuration as a service of the DI container:

services:
	- MyAuthorizator

And here is an example of usage. Note that this time we call the Nette\Security\User::isAllowed() method, not the authorizer's, so the first parameter $role is missing. This method calls MyAuthorizator::isAllowed() sequentially for all the user's roles and returns true if at least one of them has permission.

if ($user->isAllowed('file')) { // can the user do anything with the 'file' resource?
	useFile();
}

if ($user->isAllowed('file', 'delete')) { // can the user perform 'delete' on the 'file' resource?
	deleteFile();
}

Both arguments are optional; the default value null means anything.

Rules for Roles and Sections of the Site

Often you don't need your own authorizer at all. For example, only editors may enter the administration, whichever of its pages it is. Rules like these between roles and sections of the site are conveniently written in the ACL that comes with Nette. Just list them in the configuration:

security:
	roles:
		guest:
		registered: [guest]
		editor: [registered]
		admin: [registered]

	resources:
		backend:

	rules:
		allow:
			- [editor, backend]

The ACL then serves as the authorizer, so you ask in exactly the same way:

if (!$this->getUser()->isAllowed('backend')) {
	$this->error('Forbidden', 403);
}

You can read how the ACL works and everything it can do in the chapter ACL.

version: 4.x 3.x 2.x