If anybody is trying to achieve this in Drupal 8, then here's a custom module you can tweak according to your needs. This implementation grants access to the node ONLY IF the logged in user is referenced through the field attached to the node, all other users are denied access.

user_access_restrictions.info.yml

name: User access restrictions
description: Restricts access to CONTENT_TYPE nodes if user is not referenced.
package: Custom

type: module
core: 8.x

user_access_restrictions.module

use Drupal\Core\Access\AccessResult;

function user_access_restrictions_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Session\AccountInterface $account) {
  if ($node->bundle() == 'CONTENT_TYPE') {
    $users = $node->get('REFERENCE_FIELD_NAME')->getValue();
    if (!empty($users)) {
      foreach ($users as $user) {
        if ($user['target_id'] == $account->id()) {
          return AccessResult::allowed()->cachePerUser()->cacheUntilEntityChanges($node);
        }
      }
    }
    return AccessResult::forbidden()->cachePerUser()->cacheUntilEntityChanges($node);
  }
  return AccessResult::neutral();
}

Notes: CONTENT_TYPE signifies the content type machine name that has the reference field in question, REFERENCE_FIELD_NAME signifies the machine name of the user referencing field (e.g. "field_user_reference").

Comments

minff created an issue. See original summary.

minff’s picture

Status: Needs work » Active
marcoscano’s picture

You might want to replace the deprecated cacheUntilEntityChanges() method by:

return AccessResult::allowed()->cachePerUser()->addCacheableDependency($node);
marcoscano’s picture

Also, the line:

return AccessResult::forbidden()->cachePerUser()->cacheUntilEntityChanges($node);

is probably a bug, because it will prevent other modules from granting access to a given user, if the user is not referenced in that field. You should leave only either the ::allowed() or the ::neutral() returns, unless you have a real reason for denying the access to the user no matter all other site contexts and permissions.

kiwad’s picture

works well

might worth also noting that this code gives view/update/delete access to referenced user, so you might want to use something like

if($op == 'view'){...} //give access to view
if($op == 'view' || $op == 'update'){...} //view & edit permission
MrPeanut’s picture

I am looking to give update access to referenced users and view access for all users. With changes from #3 and #4, I have the following:

use Drupal\Core\Access\AccessResult;

function user_access_restrictions_node_access(\Drupal\ node\ NodeInterface $node, $op, \Drupal\ Core\ Session\ AccountInterface $account) {
  if ($node - > bundle() == 'CONTENT_TYPE') {
    $users = $node - > get('REFERENCE_FIELD_NAME') - > getValue();
    if (!empty($users)) {
      foreach($users as $user) {
        if ($user['target_id'] == $account - > id()) {
          return AccessResult::allowed() - > cachePerUser() - > addCacheableDependency($node);
        }
      }
    }
  }
  return AccessResult::neutral();
}

I'm not sure where to put if ($op == 'view' || $op == 'update') and if that will give all users view access.

avogler’s picture

Are there any plans to port this module to 8.x?

colan’s picture

Status: Active » Needs review

It sounds like we can deprecate this module in favour of Access by Reference for Drupal 8.

hansrossel’s picture

There are some other similar modules for Drupal 8
- Permissions by field
- Reference Access

marksmith’s picture

I think the modules mentioned cannot be regarded as viable alternatives to nodeaccess_userreference in many situations. Imagine the following use case:

A "Course assignment" content type should be visible only to author (= student, who can also edit / delete his content) and to particular users referenced via the fields field_teacher and field_mentor (users belong to 2 different user roles, but this is not a role based access as teacher and mentor can vary by assignment).

  1. Access by Reference "extends edit permission to a user..." which is not what we need here.
  2. Permissions by field is not suitable for the above use case either. For each instance we would need to make configurations both from the node and from the user side.
  3. Reference Access also makes content accessible by reference from the user entity side, not from the node side ("via an entity reference field on users").
  4. Nodeaccess does provide an option to set grant access on a per node / per user basis, but this needs to be done manually after the node is saved. Which is waste of time in this case.

The same is true for a simple content type "Message", where you would need a created node to be visible only to users added to a user_reference field.

W01F’s picture

Just wondering if there were any plans to port this, or if any other valid alternatives had emerged? I see the last comment was two years ago, so figured I'd gently inquire =)

gagarine’s picture

This should be straightforward to port. The module is small and well made.

I don't need it for my project at the moment. But feel free to contact me in MP if you have a budget and need this to be ported. I need to check it a bit more in detail, but it should be around 1'000$. Be aware I'm living in Switzerland, so for sure someone can certainly do it for much cheaper.

Anybody’s picture

Hi all,

as we didn't find a proper solution for this use case since the Drupal 7 modules (nodeaccess_nodereference & nodeaccess_userreference), we decided to create: https://www.drupal.org/project/entity_access_by_reference_field
as a general solution for such cases.

Feel free to have a look and help to push things forward :)