Как перенаправить анонимного пользователя в форму входа после ошибки 403?

13

Я хочу перенаправить анонимного пользователя в форму входа, если такой пользователь обнаружит ошибку 403.

Я создал подписчика на события, и это мой код, но я попал в цикл на текущей странице.

/**
   * Redirect anonymous user to login page if he encounters 404 or 403
   * response.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $response
   *   The created response object that will be returned.
   * @param string $event
   *   The string representation of the event.
   * @param \Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher $event_dispatcher
   *   Event dispatcher that lazily loads listeners and subscribers from the dependency injection
   *   container.
   */
  public function checkLoginNeeded(GetResponseEvent $response, $event, ContainerAwareEventDispatcher $event_dispatcher) {
    $routeMatch = RouteMatch::createFromRequest($response->getRequest());
    $route_name = $routeMatch->getRouteName();
    $is_anonymous = \Drupal::currentUser()->isAnonymous();
    $is_not_login = $route_name != 'user.login';

    if ($is_anonymous && $route_name == 'system.403' && $is_not_login) {
      $query = $response->getRequest()->query->all();
//      $query['destination'] = $routeMatch->getRouteObject()->getPath();
      $query['destination'] = \Drupal::url('<current>');
      $login_uri = \Drupal::url('user.login', [], ['query' => $query]);
      $returnResponse = new RedirectResponse($login_uri, Response::HTTP_FOUND);
      $response->setResponse($returnResponse);
    }
  }

Я думаю, что это связано с тем фактом, что ответ уже содержит пункт назначения (текущий uri), а system.404 и system.403 имеют высокий приоритет, который мешает мне переопределить это.

Pierre.Vriens
источник
Можете ли вы добавить весь свой класс вместо только метода?
googletorp
Есть только $ events [KernelEvents :: REQUEST] = 'checkLoginNeeded'; в методе getSubscribeedEvents ().

Ответы:

14

Я видел, что на этот вопрос никогда не отвечали, как это сделать программно. Код на самом деле работает, когда размещен в Exception Subscriber:

/src/EventSubscriber/RedirectOn403Subscriber.php:

<?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;

class RedirectOn403Subscriber extends HttpExceptionSubscriberBase {

  protected $currentUser;

  public function __construct(AccountInterface $current_user) {
    $this->currentUser = $current_user;
  }

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

  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 && $is_not_login) {
      $query = $request->query->all();
      $query['destination'] = Url::fromRoute('<current>')->toString();
      $login_uri = Url::fromRoute('user.login', [], ['query' => $query])->toString();
      $returnResponse = new RedirectResponse($login_uri);
      $event->setResponse($returnResponse);
    }
  }

}

mymodule.services.yml:

services:
  mymodule.exception403.subscriber:
    class: Drupal\mymodule\EventSubscriber\RedirectOn403Subscriber
    tags:
      - { name: event_subscriber }
    arguments: ['@current_user']
4k4
источник
4
Это работает и, вероятно, является лучшим ответом, пока соответствующие модули (включая правила) не имеют стабильных выпусков. Мне пришлось добавить -> toString () в $ query ['destination'] = Url :: fromRoute ('<current>'), чтобы заставить это работать
Колин Шиптон
2
Этот ответ заслуживает того, чтобы показываться выше!
pbonnefoi
13

Самый простой способ - найти /admin/config/system/site-informationи заполнить поле Default 403 (access denied) pageс надписьюuser/login

Kartagis
источник
7
Это хорошее решение, но оно не учитывает тот факт, что пользователь, возможно, уже вошел в систему, о чем я упоминал в описании.
9

Просто глядя на заголовок этого вопроса (= Как перенаправить пользователя на форму входа из 403? ), Есть 2 варианта сделать это без какого-либо специального кода, как описано ниже.

Вариант 1. Используйте модуль CustomError

Модуль CustomError позволяет администратору сайта создавать настраиваемые страницы ошибок для кодов состояния HTTP 403 (доступ запрещен) и 404 (не найден) без создания узлов для каждого из них. Еще несколько подробностей о его функциях (со страницы проекта):

  • Настраиваемый заголовок страницы и описания.
  • Нет заголовков автора и даты / времени, как с обычными узлами.
  • В текст страницы можно поместить любой текст в формате HTML.
  • Страницы с ошибками являются тематическими.
  • Пользователи, которые не вошли в систему и пытаются получить доступ к области, требующей входа, будут перенаправлены на страницу, к которой они пытались получить доступ после входа в систему.
  • Позволяет пользовательские перенаправления для 404 с.

Вероятно, вас заинтересует в основном часть « Пользователи, которые не вошли в систему и пытаются получить доступ к области, требующей входа в систему, будут перенаправлены на страницу, к которой они пытались получить доступ после входа в систему ».

Для D8 также доступна версия 8.x-1.x-dev для этого модуля, более подробную информацию об этом можно найти в выпуске # 2219227 .

Вариант 2. Использование модуля «Правила»

Предположим, что путь к странице «Default 403» установлен no_access(через администратора). Затем создайте правило, используя модуль « Правила », в качестве события укажите что-то вроде «После посещения узла no_access». Чтобы все правило выглядело примерно так:

  • События: после посещения узлаno_access
  • условия:

    1. У пользователя есть роль (и) -Parameter: User: [site:current-user], Roles: anonymous user
    2. НЕ Сравнение текста -Parameter: Text: [site:current-page:url], Matching text: user/login
  • Действия: перенаправление страницы -Parameter: URL: user/login

Если вы захотите это сделать, вы можете даже добавить другое действие, чтобы также отображать некоторые (информационные) сообщения в области сообщений Drupal, например, «Вы пытались посетить страницу, для которой требуется вход в систему ...».

Правда, для этого может потребоваться включить дополнительный модуль ( Правила ). Но, как показывает его растущая популярность, этот модуль, вероятно, уже включен практически на любом сайте (аналогично модулю Views ), поскольку для этого модуля существуют десятки вариантов использования.

Для D8 также доступна версия 8.x-3.x-alfa1 для этого модуля, более подробную информацию о его версии D8 можно найти в выпуске № 2574691 , который включает ссылку на выпуск правил « Правила 8.x Roadmap »

Если вышеупомянутое не помогает, тогда вы можете проверить, не может ли быть предотвращена / объяснена причина вашего цикла (или «какой-то высокий приоритет», как в вашем вопросе) чем-то похожим на ответ на вопрос « Как указать Событие правил, такое как «Контент будет« просматриваться »? ».

Pierre.Vriens
источник
4

Я думаю, что решение вашей проблемы простое. Вы можете легко создать пользовательскую страницу для 404и 403затем внутри этой страницы, перенаправить анонимных пользователей на /userстраницу.

Вы можете использовать этот код

function YOURTHEME_preprocess_page(&$vars) {
   $header = drupal_get_http_header('status'); 
   if ($header == '404 Not Found') {     
       $vars['theme_hook_suggestions'][] = 'page__404';
   }
}

Всякий раз, когда 404 происходит, вы page--404.tpl.phpбудете использованы. На этой странице используйте этот код

if(user_is_logged_in() == false){
       /// You can do anything here.
}

Как сделать заказ 403 и 404 страницы в Drupal объясняет другой способ создания страницы для 403и 404.

М ама Д
источник
5
Эй, приятель, ты должен проверить теги и код. Этот парень явно использует Drupal 8.
alexej_d
1
привет, я дал ему алгоритм, он может легко изменить его на 8формат
M ам D
3

Самый простой способ сделать это - использовать модуль Redirect 403 to User Login (его версия для D8 существует). Вот цитата об этом (со страницы проекта):

Перенаправьте страницу ошибки HTTP 403 на страницу Drupal / user / login с необязательным сообщением, которое гласит:

"Доступ запрещен! Вы должны войти, чтобы просмотреть эту страницу."

Кроме того, нужная страница добавляется в строку запроса url, так что после успешного входа в систему пользователь попадает прямо туда, откуда он первоначально пытался зайти.

Marco.b
источник
1
Почему этот ответ опущен?
Милош Кроулик
@ milos.kroulik я предполагаю , потому что речь идет о Drupal 8 , но этот модуль для 7и6
М ама D
1
Нет, этот модуль имеет версию Drupal 8 в разработке
Колин Шиптон,
1
Уверен, что отрицательное голосование было связано с тем, что ответ был «только для ссылок» (типичная причина того, что ответы были отклонены или даже удалены ...). Такие ответы, как правило, также отображаются в очереди просмотра «низкого качества ответов» ... Обратитесь к моей отредактированной версии этого ответа сейчас для расширенной его проверки (больше не рискует быть рассмотренной как ответ только по ссылке).
Pierre.Vriens
Этот ответ не принимает во внимание, если пользователь уже вошел в систему или использует сайт fast404 и 403.
0

(1) создайте узел страницы с псевдонимом типа "/my403.html"

(2) перейдите в / admin / config / system / site-information и установите "/my403.html" как страницу ошибки 403

(3) перейдите в / admin / structure / block и добавьте блок «User login» (раздел форм) в область основного контента. Ограничьте внешний вид блока страницей "my403.html" и ролью "guest".

Вот и все.

Если вам нужно больше контроля, создайте контроллер для вашей страницы 403 и вручную добавьте UserLoginForm.

С наилучшими пожеланиями, Райнер

Райнер Фейке
источник