PermissionsHashGenerator.php in Drupal 10
Same filename and directory in other branches
Namespace
Drupal\Core\SessionFile
core/lib/Drupal/Core/Session/PermissionsHashGenerator.phpView source
<?php
namespace Drupal\Core\Session;
use Drupal\Core\PrivateKey;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Site\Settings;
/**
* Generates and caches the permissions hash for a user.
*/
class PermissionsHashGenerator implements PermissionsHashGeneratorInterface {
/**
* The private key service.
*
* @var \Drupal\Core\PrivateKey
*/
protected $privateKey;
/**
* The cache backend interface to use for the persistent cache.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cache;
/**
* The cache backend interface to use for the static cache.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $static;
/**
* Constructs a PermissionsHashGenerator object.
*
* @param \Drupal\Core\PrivateKey $private_key
* The private key service.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The cache backend interface to use for the persistent cache.
* @param \Drupal\Core\Cache\CacheBackendInterface $static
* The cache backend interface to use for the static cache.
*/
public function __construct(PrivateKey $private_key, CacheBackendInterface $cache, CacheBackendInterface $static) {
$this->privateKey = $private_key;
$this->cache = $cache;
$this->static = $static;
}
/**
* {@inheritdoc}
*
* Cached by role, invalidated whenever permissions change.
*/
public function generate(AccountInterface $account) {
// User 1 is the super user, and can always access all permissions. Use a
// different, unique identifier for the hash.
if ($account
->id() == 1) {
return $this
->hash('is-super-user');
}
$sorted_roles = $account
->getRoles();
sort($sorted_roles);
$role_list = implode(',', $sorted_roles);
$cid = "user_permissions_hash:{$role_list}";
if ($static_cache = $this->static
->get($cid)) {
return $static_cache->data;
}
else {
$tags = Cache::buildTags('config:user.role', $sorted_roles, '.');
if ($cache = $this->cache
->get($cid)) {
$permissions_hash = $cache->data;
}
else {
$permissions_hash = $this
->doGenerate($sorted_roles);
$this->cache
->set($cid, $permissions_hash, Cache::PERMANENT, $tags);
}
$this->static
->set($cid, $permissions_hash, Cache::PERMANENT, $tags);
}
return $permissions_hash;
}
/**
* Generates a hash that uniquely identifies the user's permissions.
*
* @param string[] $roles
* The user's roles.
*
* @return string
* The permissions hash.
*/
protected function doGenerate(array $roles) {
// @todo Once Drupal gets rid of user_role_permissions(), we should be able
// to inject the user role controller and call a method on that instead.
$permissions_by_role = user_role_permissions($roles);
foreach ($permissions_by_role as $role => $permissions) {
sort($permissions);
// Note that for admin roles (\Drupal\user\RoleInterface::isAdmin()), the
// permissions returned will be empty ($permissions = []). Therefore the
// presence of the role ID as a key in $permissions_by_role is essential
// to ensure that the hash correctly recognizes admin roles. (If the hash
// was based solely on the union of $permissions, the admin roles would
// effectively be no-ops, allowing for hash collisions.)
$permissions_by_role[$role] = $permissions;
}
return $this
->hash(serialize($permissions_by_role));
}
/**
* Hashes the given string.
*
* @param string $identifier
* The string to be hashed.
*
* @return string
* The hash.
*/
protected function hash($identifier) {
return hash('sha256', $this->privateKey
->get() . Settings::getHashSalt() . $identifier);
}
}
Classes
Name | Description |
---|---|
PermissionsHashGenerator | Generates and caches the permissions hash for a user. |