View source
<?php
namespace Drupal\require_login\EventSubscriber;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Path\PathMatcher;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Component\Utility\UrlHelper;
use Drupal\path_alias\AliasManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\Route;
class RequireLoginSubscriber implements EventSubscriberInterface {
protected $eventException;
protected $moduleHandler;
protected $configFactory;
protected $requestStack;
protected $accountProxy;
protected $pathMatcher;
protected $messenger;
protected $currentPath;
protected $aliasManager;
protected $routeMatch;
public function __construct(ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack, AccountProxyInterface $account_proxy, MessengerInterface $messenger, PathMatcher $path_matcher, CurrentPathStack $current_path, AliasManager $alias_manager, RouteMatchInterface $route_match) {
$this->eventException = FALSE;
$this->moduleHandler = $module_handler;
$this->configFactory = $config_factory;
$this->requestStack = $request_stack;
$this->accountProxy = $account_proxy;
$this->messenger = $messenger;
$this->pathMatcher = $path_matcher;
$this->currentPath = $current_path;
$this->aliasManager = $alias_manager;
$this->routeMatch = $route_match;
}
private function checkLogin(GetResponseEvent $event, ImmutableConfig $config, Request $request) {
if ($event instanceof GetResponseForExceptionEvent) {
$exception = $event
->getException();
switch ($exception
->getStatusCode()) {
case '403':
if ($config
->get('excluded_403')) {
return FALSE;
}
break;
case '404':
if ($config
->get('excluded_404')) {
return FALSE;
}
break;
}
}
$route = $request
->get('_route_object');
if ($route instanceof Route && $route
->hasRequirement('_user_is_logged_in') && $route
->getRequirement('_user_is_logged_in') === 'FALSE') {
return FALSE;
}
$route_name = $request
->get('_route');
$default_checks = [
PHP_SAPI === 'cli',
$route_name === 'system.cron',
$route_name === 'system.db_update',
$route_name === 'user.register' || $route_name === 'user.pass' || substr($route_name, 0, 10) === 'user.reset',
$route_name === 'image.style_public' || $route_name === 'image.style_private',
];
$this->moduleHandler
->alter('require_login_authcheck', $default_checks);
if (in_array(TRUE, $default_checks)) {
return FALSE;
}
$excluded_routes = array_filter(preg_split('/\\r\\n|\\r|\\n/', $config
->get('excluded_routes')));
if (in_array($route_name, $excluded_routes)) {
return FALSE;
}
if ($route_name === 'entity.node.canonical' && ($node_types = $config
->get('excluded_node_types'))) {
if (($node = $this->routeMatch
->getParameter('node')) && in_array($node
->bundle(), $node_types, TRUE)) {
return FALSE;
}
}
$current_path = $this->currentPath
->getPath($request);
$current_path_alias = $this->aliasManager
->getAliasByPath($current_path);
$current_path_parameters = $request->query
->all();
$excluded_paths = array_filter(preg_split('/\\r\\n|\\r|\\n/', $config
->get('excluded_paths')));
$excluded_paths[] = $config
->get('auth_path');
foreach ($excluded_paths as $path) {
$path = trim($path);
$path_parts = UrlHelper::parse($path);
$path_parts['path'] = mb_strtolower($path_parts['path']);
$current_checks = [
$this->pathMatcher
->matchPath($current_path, $path_parts['path']),
$this->pathMatcher
->matchPath($current_path_alias, $path_parts['path']),
];
if (!empty($path_parts['query'])) {
if (in_array(TRUE, $current_checks)) {
if (count(array_intersect($current_path_parameters, $path_parts['query'])) === count($path_parts['query'])) {
return FALSE;
}
}
}
elseif (in_array(TRUE, $current_checks)) {
return FALSE;
}
}
return TRUE;
}
private function loginRedirect(GetResponseEvent $event) {
if ($this->accountProxy
->getAccount()
->isAuthenticated()) {
return NULL;
}
$config = $this->configFactory
->get('require_login.config');
$request = $this->requestStack
->getCurrentRequest();
if ($this
->checkLogin($event, $config, $request)) {
if ($message = $config
->get('deny_message')) {
$messenger = $this->messenger;
$messenger
->addMessage($message, $messenger::TYPE_WARNING);
}
if ($auth_path = $config
->get('auth_path')) {
$redirect_path = "internal:{$auth_path}";
}
else {
$redirect_path = 'internal:/user/login';
}
if (empty($destination = $config
->get('destination_path'))) {
$destination = $request
->getRequestUri();
}
return Url::fromUri($redirect_path, [
'query' => [
'destination' => $destination,
],
])
->toString();
}
return NULL;
}
public function exceptionRedirect(GetResponseEvent $event) {
$this->eventException = TRUE;
if ($redirect = $this
->loginRedirect($event)) {
$response = new RedirectResponse($redirect);
$event
->setResponse($response);
}
}
public function requestRedirect(GetResponseEvent $event) {
if (!$this->eventException && ($redirect = $this
->loginRedirect($event))) {
$response = new RedirectResponse($redirect);
$event
->setResponse($response);
}
}
public static function getSubscribedEvents() {
$events[KernelEvents::EXCEPTION][] = [
'exceptionRedirect',
];
$events[KernelEvents::REQUEST][] = [
'requestRedirect',
];
return $events;
}
}