NodeAccessControlHandler.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. namespace Drupal\node;
  3. use Drupal\Core\Access\AccessResult;
  4. use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
  5. use Drupal\Core\Entity\EntityHandlerInterface;
  6. use Drupal\Core\Entity\EntityTypeInterface;
  7. use Drupal\Core\Field\FieldDefinitionInterface;
  8. use Drupal\Core\Field\FieldItemListInterface;
  9. use Drupal\Core\Entity\EntityAccessControlHandler;
  10. use Drupal\Core\Entity\EntityInterface;
  11. use Drupal\Core\Session\AccountInterface;
  12. use Symfony\Component\DependencyInjection\ContainerInterface;
  13. /**
  14. * Defines the access control handler for the node entity type.
  15. *
  16. * @see \Drupal\node\Entity\Node
  17. * @ingroup node_access
  18. */
  19. class NodeAccessControlHandler extends EntityAccessControlHandler implements NodeAccessControlHandlerInterface, EntityHandlerInterface {
  20. /**
  21. * The node grant storage.
  22. *
  23. * @var \Drupal\node\NodeGrantDatabaseStorageInterface
  24. */
  25. protected $grantStorage;
  26. /**
  27. * Constructs a NodeAccessControlHandler object.
  28. *
  29. * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
  30. * The entity type definition.
  31. * @param \Drupal\node\NodeGrantDatabaseStorageInterface $grant_storage
  32. * The node grant storage.
  33. */
  34. public function __construct(EntityTypeInterface $entity_type, NodeGrantDatabaseStorageInterface $grant_storage) {
  35. parent::__construct($entity_type);
  36. $this->grantStorage = $grant_storage;
  37. }
  38. /**
  39. * {@inheritdoc}
  40. */
  41. public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
  42. return new static(
  43. $entity_type,
  44. $container->get('node.grant_storage')
  45. );
  46. }
  47. /**
  48. * {@inheritdoc}
  49. */
  50. public function access(EntityInterface $entity, $operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
  51. $account = $this->prepareUser($account);
  52. if ($account->hasPermission('bypass node access')) {
  53. $result = AccessResult::allowed()->cachePerPermissions();
  54. return $return_as_object ? $result : $result->isAllowed();
  55. }
  56. if (!$account->hasPermission('access content')) {
  57. $result = AccessResult::forbidden("The 'access content' permission is required.")->cachePerPermissions();
  58. return $return_as_object ? $result : $result->isAllowed();
  59. }
  60. $result = parent::access($entity, $operation, $account, TRUE)->cachePerPermissions();
  61. return $return_as_object ? $result : $result->isAllowed();
  62. }
  63. /**
  64. * {@inheritdoc}
  65. */
  66. public function createAccess($entity_bundle = NULL, AccountInterface $account = NULL, array $context = [], $return_as_object = FALSE) {
  67. $account = $this->prepareUser($account);
  68. if ($account->hasPermission('bypass node access')) {
  69. $result = AccessResult::allowed()->cachePerPermissions();
  70. return $return_as_object ? $result : $result->isAllowed();
  71. }
  72. if (!$account->hasPermission('access content')) {
  73. $result = AccessResult::forbidden("The 'access content' permission is required.")->cachePerPermissions();
  74. return $return_as_object ? $result : $result->isAllowed();
  75. }
  76. $result = parent::createAccess($entity_bundle, $account, $context, TRUE)->cachePerPermissions();
  77. return $return_as_object ? $result : $result->isAllowed();
  78. }
  79. /**
  80. * {@inheritdoc}
  81. */
  82. protected function checkAccess(EntityInterface $node, $operation, AccountInterface $account) {
  83. /** @var \Drupal\node\NodeInterface $node */
  84. // Fetch information from the node object if possible.
  85. $status = $node->isPublished();
  86. $uid = $node->getOwnerId();
  87. // Check if authors can view their own unpublished nodes.
  88. if ($operation === 'view' && !$status && $account->hasPermission('view own unpublished content') && $account->isAuthenticated() && $account->id() == $uid) {
  89. return AccessResult::allowed()->cachePerPermissions()->cachePerUser()->addCacheableDependency($node);
  90. }
  91. // Evaluate node grants.
  92. $access_result = $this->grantStorage->access($node, $operation, $account);
  93. if ($operation === 'view' && $access_result instanceof RefinableCacheableDependencyInterface) {
  94. // Node variations can affect the access to the node. For instance, the
  95. // access result cache varies on the node's published status. Only the
  96. // 'view' node grant can currently be cached. The 'update' and 'delete'
  97. // grants are already marked as uncacheable in the node grant storage.
  98. // @see \Drupal\node\NodeGrantDatabaseStorage::access()
  99. $access_result->addCacheableDependency($node);
  100. }
  101. return $access_result;
  102. }
  103. /**
  104. * {@inheritdoc}
  105. */
  106. protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
  107. return AccessResult::allowedIf($account->hasPermission('create ' . $entity_bundle . ' content'))->cachePerPermissions();
  108. }
  109. /**
  110. * {@inheritdoc}
  111. */
  112. protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
  113. // Only users with the administer nodes permission can edit administrative
  114. // fields.
  115. $administrative_fields = ['uid', 'status', 'created', 'promote', 'sticky'];
  116. if ($operation == 'edit' && in_array($field_definition->getName(), $administrative_fields, TRUE)) {
  117. return AccessResult::allowedIfHasPermission($account, 'administer nodes');
  118. }
  119. // No user can change read only fields.
  120. $read_only_fields = ['revision_timestamp', 'revision_uid'];
  121. if ($operation == 'edit' && in_array($field_definition->getName(), $read_only_fields, TRUE)) {
  122. return AccessResult::forbidden();
  123. }
  124. // Users have access to the revision_log field either if they have
  125. // administrative permissions or if the new revision option is enabled.
  126. if ($operation == 'edit' && $field_definition->getName() == 'revision_log') {
  127. if ($account->hasPermission('administer nodes')) {
  128. return AccessResult::allowed()->cachePerPermissions();
  129. }
  130. return AccessResult::allowedIf($items->getEntity()->type->entity->shouldCreateNewRevision())->cachePerPermissions();
  131. }
  132. return parent::checkFieldAccess($operation, $field_definition, $account, $items);
  133. }
  134. /**
  135. * {@inheritdoc}
  136. */
  137. public function acquireGrants(NodeInterface $node) {
  138. $grants = $this->moduleHandler->invokeAll('node_access_records', [$node]);
  139. // Let modules alter the grants.
  140. $this->moduleHandler->alter('node_access_records', $grants, $node);
  141. // If no grants are set and the node is published, then use the default grant.
  142. if (empty($grants) && $node->isPublished()) {
  143. $grants[] = ['realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0];
  144. }
  145. return $grants;
  146. }
  147. /**
  148. * {@inheritdoc}
  149. */
  150. public function writeGrants(NodeInterface $node, $delete = TRUE) {
  151. $grants = $this->acquireGrants($node);
  152. $this->grantStorage->write($node, $grants, NULL, $delete);
  153. }
  154. /**
  155. * {@inheritdoc}
  156. */
  157. public function writeDefaultGrant() {
  158. $this->grantStorage->writeDefault();
  159. }
  160. /**
  161. * {@inheritdoc}
  162. */
  163. public function deleteGrants() {
  164. $this->grantStorage->delete();
  165. }
  166. /**
  167. * {@inheritdoc}
  168. */
  169. public function countGrants() {
  170. return $this->grantStorage->count();
  171. }
  172. /**
  173. * {@inheritdoc}
  174. */
  175. public function checkAllGrants(AccountInterface $account) {
  176. return $this->grantStorage->checkAll($account);
  177. }
  178. }