2

I have a feature where if a user navigates to a specific url (www.mysite.com/special-content) they are redirected to the login page, where we've appended a destination to the request (www.mysite.com/user/login?destination=special-content).

We created a custom module using a checkAuthStatus event subscriber to detect anonymous users and redirect them appropriately:

$ cat src/EventSubscriber/RedirectAnonymousSubscriber.php
<?php

namespace Drupal\anon_redirect\EventSubscriber;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Event subscriber subscribing to KernelEvents::REQUEST.
 */
class RedirectAnonymousSubscriber implements EventSubscriberInterface {

  public function __construct() {
    $this->account = \Drupal::currentUser();
  }

  public function checkAuthStatus(GetResponseEvent $event) {
    $paths = [
      '/special-content',
      '/more-special-content'
    ];

    if ($this->account->isAnonymous()) {
      foreach ( $paths as $path ) {
        if ( substr($_SERVER['REQUEST_URI'], 0, strlen($path)) === $path ) {
          $url = \Drupal\Core\Url::fromUri('internal:/user/login',[
            'query'=>['destination'=>$_SERVER['REQUEST_URI']],
          ]);
          $response = new RedirectResponse('/user/login?destination='.$_SERVER['REQUEST_URI'], 302);
          $response->send();
          return;
        }
      }
    }

  }

  public static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = ['checkAuthStatus'];
    return $events;
  }
}

This has been working fine for a few months, but recently I got complains that people were not getting redirected. Upon investigation, I saw that they were getting 'access denied', as evidenced by the watchdog log. That is, when they are not logged in, they see our 301 page, instead of getting redirected.

Frustratingly, I've only been able to intermittently reproduce this problem. Sometimes I get the 301 page, sometimes I get the login page with the proper redirect query appended. I've tried both Firefox and Chrome, private sessions, clearing cookies, etc.

I suspect that whatever decides access also is listening to checkAuthStatus and sometimes having the final word about what page is ultimately sent to the end-user, and our module's behavior is not implemented, while other times, our event listener is invoked.

My question is if there is any way I can see what event listeners are subscribed to the checkAuthStatus event, and ideally, which one is having the final word as to the ultimate response from Drupal. I suspect another one is somehow getting prioritized over mine, and would like to confirm or deny that theory.

6
  • 1
    To stop the propagation of the event you have to return a response from the event subscriber, see drupal.stackexchange.com/questions/270597/…
    – 4uk4
    Commented Mar 6, 2019 at 21:15
  • @4k4 Did you link the right question? I don't see anything about stop propagation in that page.
    – user1359
    Commented Mar 7, 2019 at 13:35
  • Yes, I did. When you send the response instead of returning it (see the answer to the linked question) you don't stop the event dispatcher and Drupal continues to build its own response. This causes the erratic behavior you describe. You might need to adjust the priority of your event, I think <300 to get executed after AuthenticationSubscriber (see the list shown in the answer from @johndevman), because your code depends only on the current user.
    – 4uk4
    Commented Mar 7, 2019 at 13:51
  • @4k4 okay, but I don't see the return in the checkForRedirection() method in the answer to the question you linked. It does return $events in getSubscribedEvents(), but so does my code. Also I don't see where the priority is set in the linked question or accepted answer.
    – user1359
    Commented Mar 7, 2019 at 14:08
  • 1
    You return the response in the event object $event->setResponse($response)
    – 4uk4
    Commented Mar 7, 2019 at 14:15

2 Answers 2

6

In the above code example the event is KernelEvents::Request and checkAuthStatus is the method called when the Request event is dispatched.

You can use Drupal Console debug:event command to list all subscribers for a given event:

vendor/bin/drupal debug:event kernel.request

And that will give you something like:

  Drupal\Core\EventSubscriber\OptionsRequestSubscriber                   onRequest: 1000
  Drupal\Core\EventSubscriber\RedirectLeadingSlashesSubscriber           redirect: 1000
  Drupal\Core\EventSubscriber\AuthenticationSubscriber                   onKernelRequestAuthenticate: 300
  Drupal\language\EventSubscriber\LanguageRequestSubscriber              onKernelRequestLanguage: 255
  Drupal\Core\EventSubscriber\RedirectResponseSubscriber                 sanitizeDestination: 100
  Drupal\Core\EventSubscriber\AjaxResponseSubscriber                     onRequest: 50
  Symfony\Component\HttpKernel\EventListener\RouterListener              onKernelRequest: 32
  Drupal\Core\EventSubscriber\AuthenticationSubscriber                   onKernelRequestFilterProvider: 31
  Drupal\user\EventSubscriber\MaintenanceModeSubscriber                  onKernelRequestMaintenance: 31
  Drupal\Core\EventSubscriber\MaintenanceModeSubscriber                  onKernelRequestMaintenance: 30
  Drupal\Core\Routing\RoutePreloader                                     onRequest: 0
  Drupal\Core\EventSubscriber\ReplicaDatabaseIgnoreSubscriber            checkReplicaServer: 0

If you use Drush and have the devel module installed, you can do:

vendor/bin/drush devel-event kernel.request
1
  • drush devel-event (or drush devel:event in the current version of drush) only shows kernel events, not any other events.
    – anonymous
    Commented Jul 23, 2021 at 22:53
2

You can get a list of the subscribers to a particular event, sorted in order of priority, using the event dispatcher service:

$subscribers = \Drupal::service('event_dispatcher')
  ->getListeners(\Symfony\Component\HttpKernel\KernelEvents::REQUEST);
1
  • This returns an array of callables, which isn't very useful ...
    – anonymous
    Commented Jul 23, 2021 at 22:54

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.