0

In my D10 application, it is required that I have a parallel user login system separate from the Drupal system (it is a requirement I cannot change). On my routing, I have the following:

msul_tgif_star_xml_client.login:
  path: '/tgif/login'
  defaults:
    _title: 'TGIF Login'
    _form: 'Drupal\msul_tgif_star_xml_client\Form\LoginForm'
  requirements:
    _permission: 'access content'

msul_tgif_star_xml_client.somepage:
  path: '/somepath'
  defaults:
    _form: '\Drupal\msul_tgif_star_xml_client\Form\SomeRandomForm'
  requirements:                                                              
    _custom_access: '\Drupal\msul_tgif_star_xml_client\securityCheck::access'

msul_tgif_star_xml_client.someotherpage:
  path: '/somepath/other'
  defaults:
    _form: '\Drupal\msul_tgif_star_xml_client\Form\SomeotherRandomForm'
  requirements:                                                              
    _custom_access: '\Drupal\msul_tgif_star_xml_client\securityCheck::access'

For the access function I have:

final class securityCheck {
  public function access(AccountInterface $account, Request $request)
  {
    // Do some security checking based on factors such as IP address, tokens, etc.
    if($checkOK){
      return AccessResult::allowedIf($checkOK);
    }
    else{
      return new RedirectResponse(
                      \Drupal\Core\Url::fromRoute(
                        'msul_tgif_star_xml_client.login')
                      ->toString()
                 );
    }
  }
}

This does not work, of course, because the _access_callback demands a return type of AccessResult. How do I make the else clause redirect to the login form from the access callback?

2
  • 1
    Access callbacks can only determine access, literally nothing else - what you're describing is typically a controller (or middleware)'s job
    – Clive
    Feb 6 at 17:28
  • A negative AccessResult throws an AccessDeniedHttpException which can be caught in a kernel exception subscriber. Here you can set a redirect response, either depending on the route name or, if you want it more specific, give a reason in the returned access result and check this in the AccessDeniedHttpException when handling it.
    – 4uk4
    Feb 6 at 20:52

1 Answer 1

1

You have to return an access result, for example:

return AccessResult::forbidden('Redirect me!');

This results in an access denied exception, which you can catch in an exception subscriber:

src/EventSubscriber/MymoduleExceptionSubscriber.php

<?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

class MymoduleExceptionSubscriber extends HttpExceptionSubscriberBase {

  protected function getHandledFormats() {
    return ['html'];
  }

  public function on403(ExceptionEvent $event) {
    $exception = $event->getThrowable();
    if ($exception instanceof AccessDeniedHttpException) {
      if ($exception->getMessage() == 'Redirect me!') {
        $response = new RedirectResponse('/different/login');
        $event->setResponse($response);
      }
    }
  }

}

mymodule.services.yml

services:
  mymodule.403_subscriber:
    class: Drupal\mymodule\EventSubscriber\MymoduleExceptionSubscriber
    tags:
      - { name: event_subscriber }

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.