0

I want to trigger an event when an anonymous user comes to /user/login. I made an event subscriber, but it only fires one time:

namespace Drupal\mymodule\EventSubscriber;

use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;

/**
 * Class LoginSubscriber.
 *
 * @package Drupal\mymodule\EventSubscriber
 */
class LoginSubscriber implements EventSubscriberInterface {

  /**
   * Redirect the user before we let them access a login form.
   */
  public function onLoginRequest(GetResponseEvent $event) {
    $account= \Drupal::currentUser();

    $config = \Drupal::config('mymodule.settings');
    $base_url = \Drupal::request()->getSchemeAndHttpHost();
    $site_key = $config->get('eweb_site_key');

    switch ($config->get('mode')) {
      case 'test':
        $url = $config->get('eweb_base_test');
        break;

      case 'live':
        $url = $config->get('eweb_base_live');
        break;

      default:
        $url = $config->get('eweb_base_test');
        break;
    }

    // User is accessing login page, check for active session
    if ($event->getRequest()->getRequestUri() == '/user/login' && $account->isAnonymous() && $event->getRequest()->query->get('loginFailed') == FALSE) {
      $response = new TrustedRedirectResponse($url . '/StartPage.aspx?Site=' . $site_key . '&URL_success=' . $base_url . '/user/netforum/{token}&URL_failed=' . $base_url . '/user/login?loginFailed=true');
      return $response->send();
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = ['onLoginRequest'];
    return $events;
  }
}

The purpose is that the external site will look to see if this user has an active session, if so, it will redirect back to my site with a token and that controller will handle logging in that user with some logic and user_login_finalize.

However, it is currently only firing once.

1
  • Adding \Drupal::service('page_cache_kill_switch')->trigger(); to user login form via form alter seems to do it, but that feels dirty, but implementing my own middleware as alluded to here seems like overkill: drupal.stackexchange.com/a/237560/57 – Kevin Jul 6 '17 at 21:00
1

I agree with @Berdir, it shouldn't be a problem if the internal page cache stores a response for each query string.

But the issue here is probably that TrustedRedirectResponse is a cacheable response. When you use such a cacheable response you have to add the correct cache metadata for the content of the response, here a context for the query arg:

  if ($event->getRequest()->getRequestUri() == '/user/login' && $account->isAnonymous() && $event->getRequest()->query->get('loginFailed') == FALSE) {

    $response = new TrustedRedirectResponse($url . '/StartPage.aspx?Site=' . $site_key . '&URL_success=' . $base_url . '/user/netforum/{token}&URL_failed=' . $base_url . '/user/login?loginFailed=true');

    $cache_metadata = new CacheableMetadata();
    $cache_metadata->setCacheContexts(['url.query_args:loginFailed']);
    // or set max-age = 0 instead
    // $cache_metadata->setCacheMaxAge(0);
    $response->addCacheableDependency($cache_metadata);

    $event->setResponse($response);

    }
  }

Then the dynamic page cache will vary by this context. Or add max-age = 0 to disable the dynamic page cache, because caching won't help here much, this is already cached for anonymous users.

1
  • 1
    You could optimize it a bit and only cache by that specific query argument with url.query_args:loginFailed – Berdir Jul 6 '17 at 22:57
0

Page cache is a middleware and happens outside of event subscribers.

You could implement that logic in JS for example.

But it's not exactly clear to me why it is even a problem that it is only called once. The internal page cache will cache that for the exact URL and will always return a redirect and not a redirect with the login failed query argument. is that a problem?

Not 100% sure about the dynamic page cache, if that caches the request as well (you can easily see that based on the headers and/or the cache_dynamic_page_cache table), then you need to add a cache context for that query argument.

3
  • Well, I went to the page, and my breakpoint triggered. I went back again, and it did not. To me it seemed like it only fired that code once, unless I missed something. After adding the killswitch trigger, the breakpoint hit every time. – Kevin Jul 6 '17 at 21:02
  • Yes, it is cached. My point is that this is not actually a problem because it should redirect or not as expected? So if that's all your doing, then it should just work and it doesn't matter that it is actually cached. And if it results in an endless loop or so in case of a fail then that might be due to dynamic page cache – Berdir Jul 6 '17 at 21:12
  • Should always redirect if anonymous and the query string parameter is false or does not exist – Kevin Jul 6 '17 at 21:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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