2

I need to disable the "administrator" role from user accounts who log into my website from outside my network. For security, I only want users who have this role to be able to use it when they are on my network (determined by some custom PHP code I have).

I know I can remove a role from a user permanently using the appropriate entity methods like this:

<?php
use Drupal\user\Entity\User;

$user = User::load(\Drupal::currentUser()->id());
$user->removeRole('administrator');
$user->save();

But what about to do so temporarily, without updating the user permanently?

Looking at changes made to a user's roles in a custom module using hook_user_login() are permanent. In Drupal 7, I was able to achieve this by modifying the global $user->roles in various hooks.

I am also open to other ways Drupal allows me to meet my needs.

1

1 Answer 1

3

Instead of a Drupal 7 hook you can use the new AccountEvents::SET_USER event:

/src/EventSubscriber/SetAccountSubscriber.php

<?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\Session\AccountEvents;
use Drupal\Core\Session\AccountSetEvent;
use Drupal\Core\Session\UserSession;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * mymodule event subscriber.
 */
class SetAccountSubscriber implements EventSubscriberInterface {

  /**
   * Account set event handler.
   *
   * @param Drupal\Core\Session\AccountSetEvent $event
   *   Account set event.
   */
  public function onAccountSet(AccountSetEvent $event) {
    $account = $event->getAccount();
    if ($account->isAuthenticated()) {
      $roles = $account->getRoles();
      if (in_array('administrator', $roles)) {
        $roles = array_values(array_diff($roles, ['administrator']));
        $account = new UserSession([
          'uid' => $account->id(),
          'access' => $account->getLastAccessedTime(),
          'roles' => $roles,
          'name' => $account->getAccountName(),
          'preferred_langcode' => $account->getPreferredLangcode(),
          'preferred_admin_langcode' => $account->getPreferredAdminLangcode(),
          'mail' => $account->getEmail(),
          'timezone' => $account->getTimeZone(),
        ]);
        \Drupal::currentUser()->setAccount($account);
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      AccountEvents::SET_USER => ['onAccountSet'],
    ];
  }

}

mymodule.services.yml

services:
  mymodule.set_account_subscriber:
    class: Drupal\mymodule\EventSubscriber\SetAccountSubscriber
    tags:
      - { name: event_subscriber }  

Be careful to avoid an infinite loop. The last line dispatches the event again and you need a condition preventing the line to be executed a second time, in this case through the removed role.

Your Answer

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

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