1

Following a suggestion in another thread here I'm trying to rewrite the access restrictions that I developed using hook_node_access (and that are working well, so far) in Drupal's grant system (i.e. using hook_node_access_records and hook_node_grants). I would like to do that for two reasons:

  1. I'm worried that the current access checks might become a performance bottleneck, when the number of users grows.
  2. I need to use the results of access checks as a filter in views.

Here's a truncated version of my current access checks:

function mymodule_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Session\AccountInterface $account){
  $type = $node->bundle();
  $user = $account->getAccount();
  $uid = $user->id();

  // only handle the lesson content type
  if ($type === 'lesson') {

    // ...

    // check the user's access to the referring courses
    $courseaccess = FALSE;
    if ($node->hasField('reverse_entity_reference')) {
      $parentcourses = $node->get('reverse_entity_reference')->getValue();
      foreach ($parentcourses as $course) {
        $coursenode = \Drupal\node\Entity\Node::load($course['target_id']);
        // perform access checks for the referring course
        $courseaccess = $courseaccess || ...
      }
    }

    // ...

    // return the result
    if ($courseaccess) {
      return AccessResult::allowed();
    } else {
      return AccessResult::forbidden();
    }
  }

  // ...

}

Note that, in essence, I need to check, whether the current user has access to any of the nodes (courses) that are referring to the viewed node (lessons): That determines, whether the user may access the lesson. I'm using reverse entity references for that.

As I see it (I'm open to suggestions), there are fundamentally two ways for approaching this. Unfortunately, so far, I have been unable to solve the problems involved. So, in my understanding, I could...

  1. Put (more or less) the full access logic into hook_node_grants: That would mean, I need to have access to the currently viewed node (lesson) in hook_node_grants to be able to follow its reverse references to check, whether the user has access to any of the referring nodes. Is that possible? There's no $node variable...
  2. Put (more or less) the full access logic into hook_node_access_records: In that case, the problem is that the hook only gets called (and thus the lesson gets updated), whenever the node is saved. So, the access restrictions will be out of date, as soon as a lesson is included in another course.

I'm unsure how to proceed at this point. Is it even possible to rewrite this in the grant system? Any other ideas?

1 Answer 1

1

Given that we don't have an exhaustive list of requirements & Q&A isn't suited well for long discussions, it will be impossible to definitely say yes.

The grant system isn't designed around any sort idea of hierarchy. Is it possible to rewrite? It depends if you can refactor your existing logic around what the grant system supplies.

You've framed your question as a dilemma, but you really need both hooks to use the grant system:

  • hook_node_grants need to assign realm/gid grants that correspond to the $user and the available lesson nid they can access.
  • hook_node_access_records needs to fire against a lesson $node

So if you can:

  • Map the realm/gid grant keys to match to courses the user has access to (e.g. mymodule_course_realm/123 where 123 some group identifier that maps to a group of users that have course access, thus lesson nid access)
  • Trigger lesson save events upon course updates (e.g. using hook_node_update, hook_node_insert, etc. to look for update courses, then doing dummy saves on the lesson nodes) so that hook_node_access_records can fire against lesson nodes that have a changed relationship. (or build custom logic where you insert grants directly via NodeGrantDatabaseStorage::write())

You can probably refactor around the hooks the grant system provides.

1
  • Thank you very much for the detailed answer. I was afraid this might be the bottom line. I had already thought of triggering lesson save events, but am worried that this might cause inefficiencies and inconsistencies down the road. Which is why I was hoping for a way to get access to the $node variable in hook_node_grants. Sadly, refactoring the system seems unrealistic, as the flexibility is important: I.e., if a lesson is part of two courses, only one of which the user may access, the lesson should be accessible in both courses! Thanks anyway, much appreciated!
    – Marcus C.
    Apr 29, 2020 at 9:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.