Chris@18: access('view')` is how entity access is checked. Chris@18: * This call invokes the corresponding hooks. However, these access checks Chris@18: * require an `$entity` object. This means that they cannot be called prior to Chris@18: * executing a database query. Chris@18: * Chris@18: * In order to safely enable filtering across a relationship, modules Chris@18: * responsible for entity access must do two things: Chris@18: * - Implement this hook (or hook_jsonapi_ENTITY_TYPE_filter_access()) and Chris@18: * return an array of AccessResults keyed by the named entity subsets below. Chris@18: * - If the AccessResult::allowed() returned by the above hook does not provide Chris@18: * enough granularity (for example, if access depends on a bundle field value Chris@18: * of the entity being queried), then hook_query_TAG_alter() must be Chris@18: * implemented using the 'entity_access' or 'ENTITY_TYPE_access' query tag. Chris@18: * See node_query_node_access_alter() for an example. Chris@18: * Chris@18: * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type Chris@18: * The entity type of the entity to be filtered upon. Chris@18: * @param \Drupal\Core\Session\AccountInterface $account Chris@18: * The account for which to check access. Chris@18: * Chris@18: * @return \Drupal\Core\Access\AccessResultInterface[] Chris@18: * An array keyed by a constant which identifies a subset of entities. For Chris@18: * each subset, the value is one of the following access results: Chris@18: * - AccessResult::allowed() if all entities within the subset (potentially Chris@18: * narrowed by hook_query_TAG_alter() implementations) are viewable. Chris@18: * - AccessResult::forbidden() if any entity within the subset is not Chris@18: * viewable. Chris@18: * - AccessResult::neutral() if the implementation has no opinion. Chris@18: * The supported subsets for which an access result may be returned are: Chris@18: * - JSONAPI_FILTER_AMONG_ALL: all entities of the given type. Chris@18: * - JSONAPI_FILTER_AMONG_PUBLISHED: all published entities of the given type. Chris@18: * - JSONAPI_FILTER_AMONG_ENABLED: all enabled entities of the given type. Chris@18: * - JSONAPI_FILTER_AMONG_OWN: all entities of the given type owned by the Chris@18: * user for whom access is being checked. Chris@18: * See the documentation of the above constants for more information about Chris@18: * each subset. Chris@18: * Chris@18: * @see hook_jsonapi_ENTITY_TYPE_filter_access() Chris@18: */ Chris@18: function hook_jsonapi_entity_filter_access(\Drupal\Core\Entity\EntityTypeInterface $entity_type, \Drupal\Core\Session\AccountInterface $account) { Chris@18: // For every entity type that has an admin permission, allow access to filter Chris@18: // by all entities of that type to users with that permission. Chris@18: if ($admin_permission = $entity_type->getAdminPermission()) { Chris@18: return ([ Chris@18: JSONAPI_FILTER_AMONG_ALL => AccessResult::allowedIfHasPermission($account, $admin_permission), Chris@18: ]); Chris@18: } Chris@18: } Chris@18: Chris@18: /** Chris@18: * Controls access to filtering by entity data via JSON:API. Chris@18: * Chris@18: * This is the entity-type-specific variant of Chris@18: * hook_jsonapi_entity_filter_access(). For implementations with logic that is Chris@18: * specific to a single entity type, it is recommended to implement this hook Chris@18: * rather than the generic hook_jsonapi_entity_filter_access() hook, which is Chris@18: * called for every entity type. Chris@18: * Chris@18: * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type Chris@18: * The entity type of the entities to be filtered upon. Chris@18: * @param \Drupal\Core\Session\AccountInterface $account Chris@18: * The account for which to check access. Chris@18: * Chris@18: * @return \Drupal\Core\Access\AccessResultInterface[] Chris@18: * The array of access results, keyed by subset. See Chris@18: * hook_jsonapi_entity_filter_access() for details. Chris@18: * Chris@18: * @see hook_jsonapi_entity_filter_access() Chris@18: */ Chris@18: function hook_jsonapi_ENTITY_TYPE_filter_access(\Drupal\Core\Entity\EntityTypeInterface $entity_type, \Drupal\Core\Session\AccountInterface $account) { Chris@18: return ([ Chris@18: JSONAPI_FILTER_AMONG_ALL => AccessResult::allowedIfHasPermission($account, 'administer llamas'), Chris@18: JSONAPI_FILTER_AMONG_PUBLISHED => AccessResult::allowedIfHasPermission($account, 'view all published llamas'), Chris@18: JSONAPI_FILTER_AMONG_OWN => AccessResult::allowedIfHasPermissions($account, ['view own published llamas', 'view own unpublished llamas'], 'AND'), Chris@18: ]); Chris@18: } Chris@18: Chris@18: /** Chris@18: * Restricts filtering access to the given field. Chris@18: * Chris@18: * Some fields may contain sensitive information. In these cases, modules are Chris@18: * supposed to implement hook_entity_field_access(). However, this hook receives Chris@18: * an optional `$items` argument and often must return AccessResult::neutral() Chris@18: * when `$items === NULL`. This is because access may or may not be allowed Chris@18: * based on the field items or based on the entity on which the field is Chris@18: * attached (if the user is the entity owner, for example). Chris@18: * Chris@18: * Since JSON:API must check field access prior to having a field item list Chris@18: * instance available (access must be checked before a database query is made), Chris@18: * it is not sufficiently secure to check field 'view' access alone. Chris@18: * Chris@18: * This hook exists so that modules which cannot return Chris@18: * AccessResult::forbidden() from hook_entity_field_access() can still secure Chris@18: * JSON:API requests where necessary. Chris@18: * Chris@18: * If a corresponding implementation of hook_entity_field_access() *can* be Chris@18: * forbidden for one or more values of the `$items` argument, this hook *MUST* Chris@18: * return AccessResult::forbidden(). Chris@18: * Chris@18: * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition Chris@18: * The field definition of the field to be filtered upon. Chris@18: * @param \Drupal\Core\Session\AccountInterface $account Chris@18: * The account for which to check access. Chris@18: * Chris@18: * @return \Drupal\Core\Access\AccessResultInterface Chris@18: * The access result. Chris@18: */ Chris@18: function hook_jsonapi_entity_field_filter_access(\Drupal\Core\Field\FieldDefinitionInterface $field_definition, \Drupal\Core\Session\AccountInterface $account) { Chris@18: if ($field_definition->getTargetEntityTypeId() === 'node' && $field_definition->getName() === 'field_sensitive_data') { Chris@18: $has_sufficient_access = FALSE; Chris@18: foreach (['administer nodes', 'view all sensitive field data'] as $permission) { Chris@18: $has_sufficient_access = $has_sufficient_access ?: $account->hasPermission($permission); Chris@18: } Chris@18: return AccessResult::forbiddenIf(!$has_sufficient_access)->cachePerPermissions(); Chris@18: } Chris@18: return AccessResult::neutral(); Chris@18: } Chris@18: Chris@18: /** Chris@18: * @} End of "addtogroup hooks". Chris@18: */