0

For a client's website I have these URLs:

library
library/{category}

I have a ParamConverter to verify that {category} is correct and return the taxonomy term. And each URL requires a "view library" permission which anonymous doesn't have.

The client's requirements are that 404 errors redirect the user to the login page if not logged in.

I created a RedirectOn404Subscriber event subscriber to handle the 404 and redirect as needed. (I have tested it with a logged-in user and can redirect using this.)

When not logged in the redirection works fine for any obvious URL error:

example.com/xxxxx

And works for these:

example.com/library
example.com/library/valid-category

But this does not redirect:

example.com/library/invalid-category

It generates the 404 error but does not hit the redirect code.

It's as if it's not executing the ParamConverter when it's wrong - but it can't know that until it's executed the code...

Clearing caches just prior to a test does not alter the behaviour.

UPDATED TO INCLUDE CODE

404 redirect...

  /**
   * Prevents this being called when it's not an HTML request.
   *
   * @return array
   */
  protected function getHandledFormats() {
    return ['html'];
  }

  /**
   * Specifies the priority of all listeners in this class.
   *
   * The default priority is 1, which is very low. To have listeners that have
   * a "first attempt" at handling exceptions return a higher priority.
   *
   * @return int
   *   The event priority of this subscriber.
   */
  protected static function getPriority() {
    return 750;
  }

  /**
   *
   *
   * @param GetResponseForExceptionEvent $event
   */
  public function on404(GetResponseForExceptionEvent $event) {
    if ($this->currentUser->isAnonymous()) {
      // Any 404 when not logged in, return to front page.
      $route_name = '<front>';
    }
    else {
      // Any 404 when logged in, return to base page for user.
      #$route_name = 'user.page';
      return;
    }

    $query = $event->getRequest()->query->all();
    $redirect_uri = Url::fromRoute($route_name, [], ['query' => $query]);

    $returnResponse = new RedirectResponse($redirect_uri->toString());
    $event->setResponse($returnResponse);
  }

403 redirect...

  public function on403(GetResponseForExceptionEvent $event) {
    $request = $event->getRequest();
    $is_anonymous = $this->currentUser->isAnonymous();
    $route_name = $request->attributes->get('_route');
    $is_not_login = $route_name != 'user.login';
    if ($is_anonymous) {
      if ($is_not_login) {
        $query = $request->query->all();
        $redirect_uri = Url::fromRoute('<front>', [], ['query' => $query])->toString();
      }
      else {
        // Do not redirect, this is an anonymous login.
        $redirect_uri = NULL;
      }
    }
    else {
      // Any 403 when logged in, return to base page for user.
      #$redirect_uri = Url::fromRoute('user.page')->toString();
      return;
    }

    if (!empty($redirect_uri)) {
      $returnResponse = new RedirectResponse($redirect_uri);
      $event->setResponse($returnResponse);
    }
  }
1
  • Can you post the code for the ParamConverter and 404 subscriber? Sep 6, 2018 at 21:35

1 Answer 1

0

Pasting the code made me think about the problem in more detail.

It's a question of which gets sent first: 403 (Access Denied) or 404 (Page Not Found).

If it's a legal URL ("library" or "library/valid-category") but the user doesn't have access, they get a 403 and redirected.

If it's not a legal URL ("library/invalid-category") it gets reported as a 404 ... even though they don't have access anyway.

Makes sense.

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.