Jak przekierować anonimowego użytkownika do formularza logowania po błędzie 403?

13

Chcę przekierować anonimowego użytkownika do formularza logowania, jeśli taki użytkownik napotka błąd 403.

Utworzyłem subskrybenta zdarzenia i to jest mój kod, ale kończę na pętli na bieżącej stronie.

/**
   * 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);
    }
  }

Myślę, że jest to związane z faktem, że odpowiedź zawiera już miejsce docelowe (bieżące URI), a system.404 i system.403 mają jakiś wysoki priorytet, który uniemożliwia mi to pominięcie.

Pierre.Vriens
źródło
Czy możesz dodać całą klasę zamiast samej metody?
googletorp
Jest tylko $ events [KernelEvents :: REQUEST] = 'checkLoginNeeded'; w metodzie getSubscribeEvents ().

Odpowiedzi:

14

Widziałem, że na to pytanie nigdy nie udzielono odpowiedzi, jak to zrobić programowo. Kod faktycznie działa, gdy jest umieszczony w subskrybencie wyjątku:

/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
źródło
4
To działa i jest prawdopodobnie najlepszą odpowiedzią, dopóki odpowiednie moduły (łącznie z regułami) nie będą miały stabilnych wydań. Musiałem dodać -> toString () do $ query ['destination'] = Url :: fromRoute ('<current>'), aby to zadziałało
Colin Shipton
2
Ta odpowiedź zasługuje na pokazanie się wyżej!
pbonnefoi
13

Najprostszym sposobem jest, aby odszukać /admin/config/system/site-informationi wypełnić pola, który odczytuje Default 403 (access denied) pagezuser/login

Kartagis
źródło
7
To dobre rozwiązanie, ale nie uwzględnia faktu, że użytkownik może być już zalogowany, o czym wspomniałem w opisie.
9

Wystarczy spojrzeć na tytuł tego pytania (= Jak przekierować użytkownika do formularza logowania z 403? ), Istnieją 2 opcje, aby to zrobić bez żadnego niestandardowego kodu, jak opisano poniżej.

Opcja 1: Użyj modułu CustomError

CustomErrors moduł pozwala administratorowi witryny do tworzenia własnych stron błędów HTTP Kody statusu 403 (odmowa dostępu) oraz 404 (nie znaleziono), bez tworzenia węzłów dla każdego z nich. Kilka dodatkowych szczegółów na temat jego funkcji (ze strony projektu):

  • Konfigurowalny tytuł strony i opisy.
  • Nie ma nagłówków autora i daty / godziny, jak w przypadku normalnych węzłów.
  • Każdy tekst sformatowany w HTML można umieścić w treści strony.
  • Strony błędów są tematyczne.
  • Użytkownicy, którzy nie są zalogowani i próbują uzyskać dostęp do obszaru wymagającego zalogowania, zostaną przekierowani na stronę, do której próbowali uzyskać dostęp po zalogowaniu.
  • Umożliwia niestandardowe przekierowania na 404s.

Prawdopodobnie zainteresuje Cię przede wszystkim część „ Użytkownicy, którzy nie są zalogowani i spróbują uzyskać dostęp do obszaru wymagającego zalogowania, zostaną przekierowani na stronę, do której próbowali uzyskać dostęp po zalogowaniu ”.

Dla D8 dostępna jest również wersja 8.x-1.x-dev dla tego modułu, więcej szczegółów na ten temat można znaleźć w numerze # 2219227 .

Opcja 2: użyj modułu Reguły

Załóżmy, że ścieżka strony „Domyślne 403” jest ustawiona na no_access(przez administratora). Następnie utwórz regułę za pomocą modułu Reguły , używając jako zdarzenia czegoś takiego jak „Po odwiedzeniu węzła no_access”. Aby cała reguła wyglądała mniej więcej tak:

  • Wydarzenia: po wizycie w węźleno_access
  • Warunki:

    1. Użytkownik ma role (role) -Parameter: User: [site:current-user], Roles: anonymous user
    2. NIE Porównanie tekstu -Parameter: Text: [site:current-page:url], Matching text: user/login
  • Działania: Przekierowanie strony -Parameter: URL: user/login

Jeśli chcesz to zrobić, możesz nawet dodać kolejną akcję, aby wyświetlić również (informacyjną) wiadomość w obszarze wiadomości Drupal, na przykład „Próbowałeś odwiedzić stronę, dla której wymagane jest logowanie ...”.

To prawda, że ​​może wymagać włączenia dodatkowego modułu ( Reguły ). Ale, jak wskazuje jego rosnąca popularność, moduł ten prawdopodobnie jest już włączony w większości witryn (podobnie jak moduł Widoki ), ponieważ istnieją dziesiątki przypadków użycia tego modułu.

W przypadku D8 dostępna jest również wersja 8.x-3.x-alfa1 dla tego modułu, więcej szczegółów na temat jego wersji D8 można znaleźć w numerze 2574691 , który zawiera link do wydania regulaminuPlan działania 8.x

Jeśli powyższe nie pomoże, możesz sprawdzić, czy nie można zapobiec / wyjaśnić przyczyny swojej pętli (lub „wysokiego priorytetu” jak w pytaniu) przez odpowiedź podobną do odpowiedzi na pytanie „ Jak określić wydarzenie Zasad, takie jak „Treść” będzie „oglądana”? ”.

Pierre.Vriens
źródło
4

Myślę, że rozwiązanie twojego problemu jest proste. Możesz łatwo utworzyć niestandardową stronę, 404a 403następnie wewnątrz tej strony, przekierować anonimowych użytkowników na /userstronę.

Możesz użyć tego kodu

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

Ilekroć wystąpi 404, page--404.tpl.phpzostaniesz wykorzystany. Na tej stronie użyj tego kodu

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

Jak zwyczaj 403 i 404 w Drupal wyjaśnia inną metodę tworzenia strony dla 403i 404.

M ama D.
źródło
5
Hej kolego, powinieneś sprawdzić tagi i kod. Ten facet wyraźnie używa Drupala 8.
alexej_d
1
cześć, dałem mu algorytm, on może łatwo zmienić go na 8format
M am D D
3

Najprostszym sposobem na to jest skorzystanie z modułu Przekieruj 403 na login użytkownika (istnieje jego wersja deweloperska dla D8). Oto cytat na ten temat (ze strony projektu):

Przekieruj stronę błędu HTTP 403 na stronę Drupal / user / login z opcjonalnym komunikatem o treści:

„Odmowa dostępu! Musisz się zalogować, aby wyświetlić tę stronę”.

Ponadto żądana strona jest dodawana do ciągu zapytania adresu URL, aby po udanym zalogowaniu użytkownik został zabrany bezpośrednio tam, gdzie pierwotnie próbował się udać.

Marco.b
źródło
1
Dlaczego ta odpowiedź została odrzucona?
Miloš Kroulík
@ milos.kroulik Chyba dlatego, że pytanie jest o Drupal 8, ale że moduł jest dla 7i6
M ama D
1
Nie, ten moduł ma opracowaną wersję Drupal 8
Colin Shipton
1
Dość pewna, że ​​głosowanie było spowodowane tym, że odpowiedź była odpowiedzią „tylko link” (typowy powód, dla którego odpowiedzi były odrzucane, a nawet usuwane ...). Takie odpowiedzi zwykle pojawiają się również w kolejce sprawdzania odpowiedzi „niskiej jakości” ... Zapoznaj się z moją edytowaną wersją tej odpowiedzi, aby uzyskać ulepszoną wersję (już nie ma ryzyka, że ​​zostaniesz uznany za odpowiedź tylko za pomocą linku).
Pierre.Vriens
Ta odpowiedź nie bierze pod uwagę, jeśli użytkownik jest już zalogowany lub jeśli witryna korzysta z fast404 i 403.
0

(1) utwórz węzeł strony z aliasem takim jak „/my403.html”

(2) przejdź do / admin / config / system / site-information i ustaw „/my403.html” jako stronę błędu 403

(3) przejdź do / admin / structure / block i dodaj blok „User login” (Sec. Forms) do głównego regionu zawartości. Ogranicz wygląd bloku do strony „my403.html” i roli „gość”.

Otóż ​​to.

Jeśli potrzebujesz większej kontroli, utwórz kontroler dla swojej strony 403 i ręcznie dodaj UserLoginForm.

Z pozdrowieniami, Rainer

Rainer Feike
źródło