diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php index cbe6e2e212c..a830d97bacc 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php @@ -45,19 +45,24 @@ class EntityResource extends ResourceBase { * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function get(EntityInterface $entity) { - if (!$entity->access('view')) { + $entity_access = $entity->access('view', NULL, TRUE); + if (!$entity_access->isAllowed()) { throw new AccessDeniedHttpException(); } + + $response = new ResourceResponse($entity, 200); + $response->addCacheableDependency($entity); + $response->addCacheableDependency($entity_access); foreach ($entity as $field_name => $field) { - if (!$field->access('view')) { + /** @var \Drupal\Core\Field\FieldItemListInterface $field */ + $field_access = $field->access('view', NULL, TRUE); + $response->addCacheableDependency($field_access); + + if (!$field_access->isAllowed()) { $entity->set($field_name, NULL); } } - $response = new ResourceResponse($entity, 200); - // Make the response use the entity's cacheability metadata. - // @todo include access cacheability metadata, for the access checks above. - $response->addCacheableDependency($entity); return $response; } diff --git a/core/modules/rest/src/Tests/PageCacheTest.php b/core/modules/rest/src/Tests/PageCacheTest.php index 3ae008450bb..5fc6ec3883e 100644 --- a/core/modules/rest/src/Tests/PageCacheTest.php +++ b/core/modules/rest/src/Tests/PageCacheTest.php @@ -33,6 +33,7 @@ class PageCacheTest extends RESTTestBase { // Create an entity programmatically. $entity = $this->entityCreate('entity_test'); + $entity->set('field_test_text', 'custom cache tag value'); $entity->save(); // Read it over the REST API. $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType); @@ -40,6 +41,7 @@ class PageCacheTest extends RESTTestBase { $this->assertHeader('x-drupal-cache', 'MISS'); $this->assertCacheTag('config:rest.settings'); $this->assertCacheTag('entity_test:1'); + $this->assertCacheTag('entity_test_access:field_test_text'); // Read it again, should be page-cached now. $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType); @@ -47,6 +49,7 @@ class PageCacheTest extends RESTTestBase { $this->assertHeader('x-drupal-cache', 'HIT'); $this->assertCacheTag('config:rest.settings'); $this->assertCacheTag('entity_test:1'); + $this->assertCacheTag('entity_test_access:field_test_text'); // Trigger a config save which should clear the page cache, so we should get // a cache miss now for the same request. @@ -56,6 +59,7 @@ class PageCacheTest extends RESTTestBase { $this->assertHeader('x-drupal-cache', 'MISS'); $this->assertCacheTag('config:rest.settings'); $this->assertCacheTag('entity_test:1'); + $this->assertCacheTag('entity_test_access:field_test_text'); } } diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module index 19e42374e89..0eec45d75e4 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.module +++ b/core/modules/system/tests/modules/entity_test/entity_test.module @@ -384,10 +384,13 @@ function entity_test_entity_field_access($operation, FieldDefinitionInterface $f if ($field_definition->getName() == 'field_test_text') { if ($items) { if ($items->value == 'no access value') { - return AccessResult::forbidden()->cacheUntilEntityChanges($items->getEntity()); + return AccessResult::forbidden()->addCacheableDependency($items->getEntity()); + } + elseif ($items->value == 'custom cache tag value') { + return AccessResult::allowed()->addCacheableDependency($items->getEntity())->addCacheTags(['entity_test_access:field_test_text']); } elseif ($operation == 'edit' && $items->value == 'no edit access value') { - return AccessResult::forbidden()->cacheUntilEntityChanges($items->getEntity()); + return AccessResult::forbidden()->addCacheableDependency($items->getEntity()); } } }