¿Cómo redirigir a un usuario anónimo al formulario de inicio de sesión después de un error 403?

13

Quiero redirigir a un usuario anónimo al formulario de inicio de sesión si dicho usuario encuentra un error 403.

He creado un suscriptor de eventos y este es mi código, pero termino en bucle en la página actual.

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

Creo que esto está relacionado con el hecho de que la respuesta ya contiene el destino (uri actual) y system.404 y system.403 tienen una alta prioridad que me impide anular esto.

Pierre.Vriens
fuente
¿Puedes agregar toda tu clase en lugar de solo el método?
googletorp
Solo hay $ eventos [KernelEvents :: REQUEST] = 'checkLoginNeeded'; en el método getSubscriptionsEvents ().

Respuestas:

14

He visto que esta pregunta nunca fue respondida cómo hacer esto mediante programación. El código realmente funciona, cuando se coloca en un suscriptor de excepción:

/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
fuente
44
Esto funciona y es probablemente la mejor respuesta hasta que los módulos relevantes (reglas incluidas) tengan versiones estables. Tuve que agregar -> toString () a $ query ['destination'] = Url :: fromRoute ('<current>') para que esto funcione
Colin Shipton
2
¡Esta respuesta merece aparecer más alto!
pbonnefoi
13

La forma más fácil es navegar /admin/config/system/site-informationy completar el campo que lee Default 403 (access denied) pageconuser/login

Kartagis
fuente
77
Esa es una buena solución, pero no tiene en cuenta el hecho de que el usuario ya puede haber iniciado sesión, como mencioné en la descripción.
9

Simplemente mirando el título de esta pregunta (= ¿Cómo redirigir al usuario al formulario de inicio de sesión desde 403? ), Hay 2 opciones para hacerlo, sin ningún código personalizado, como se detalla a continuación.

Opción 1: usar el módulo CustomError

El módulo CustomError permite al administrador del sitio crear páginas de error personalizadas para los códigos de estado HTTP 403 (acceso denegado) y 404 (no encontrado), sin crear nodos para cada uno de ellos. Algunos detalles más sobre sus características (de su página de proyecto):

  • Título de página configurable y descripciones.
  • No hay encabezados de autor y fecha / hora como con los nodos normales.
  • Cualquier texto con formato HTML se puede poner en el cuerpo de la página.
  • Las páginas de error son temáticas.
  • Los usuarios que no hayan iniciado sesión e intenten acceder a un área que requiere inicio de sesión serán redirigidos a la página a la que intentaban acceder después de iniciar sesión.
  • Permite redireccionamientos personalizados para 404s.

Probablemente le interesará principalmente la parte sobre " Los usuarios que no han iniciado sesión e intentan acceder a un área que requiere inicio de sesión serán redirigidos a la página a la que intentaban acceder después de iniciar sesión ".

Para D8 hay una versión 8.x-1.x-dev disponible para este módulo también disponible, se pueden encontrar más detalles al respecto en el número 2219227 .

Opción 2: usar el módulo Reglas

Suponga que la ruta de la página "403 predeterminada" está establecida en no_access(a través de admin). Luego cree una regla usando el módulo Reglas , con un evento como "Después de visitar el nodo no_access". Para que toda la regla se vea así:

  • Eventos: después de visitar el nodono_access
  • Condiciones:

    1. El usuario tiene roles :Parameter: User: [site:current-user], Roles: anonymous user
    2. NO Comparación de texto -Parameter: Text: [site:current-page:url], Matching text: user/login
  • Acciones: redireccionamiento de página -Parameter: URL: user/login

Si desea hacerlo, incluso podría agregar otra Acción para mostrar también algún mensaje (informativo) en el área de mensajes de Drupal, con algo como "Intentó visitar una página para la que es necesario iniciar sesión ...".

Es cierto que puede requerir que habilite un módulo contribuido adicional ( Reglas ). Pero, como lo indica su creciente popularidad también, ese módulo probablemente ya esté habilitado en casi cualquier sitio (similar al módulo Vistas ), porque hay docenas de casos de uso para este módulo.

Para D8 hay una versión 8.x-3.x-alfa1 disponible para este módulo también, se pueden encontrar más detalles sobre su versión D8 en el número 2574691 , que incluye un enlace a la cuestión de reglas " Hoja de ruta de las reglas 8.x "

Si lo anterior no ayuda, es posible que desee verificar si el motivo de su ciclo (o "alguna prioridad alta" como en su pregunta) no puede evitarse / explicarse por algo similar a la respuesta a la pregunta " Cómo especificar un evento de Reglas como "¿El contenido se 'va a ver'? ".

Pierre.Vriens
fuente
4

Supongo que la solución a su problema es simple. Puede crear fácilmente una página personalizada para, 404y 403luego dentro de esta página, redirigir a los usuarios anónimos a la /userpágina.

Puedes usar este código

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

Siempre que ocurra 404 se page--404.tpl.phpusará tu . En esta página usa este código

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

La página Cómo crear páginas 403 y 404 personalizadas en Drupal explica otro método para crear una página para 403y 404.

M ama D
fuente
55
Hola amigo, deberías revisar las etiquetas y el código. Este tipo claramente está usando Drupal 8.
alexej_d
1
hola, le di el algoritmo, puede cambiarlo fácilmente a 8formato
M ama D
3

La forma más fácil de hacerlo es usar el módulo Redirect 403 to User Login (existe una versión dev para D8). Aquí hay una cita al respecto (de su página de proyecto):

Redireccione la página de error HTTP 403 a la página Drupal / usuario / inicio de sesión con un mensaje opcional que dice:

"¡Acceso denegado! Debe iniciar sesión para ver esta página".

Además, la página deseada se agrega en la cadena de consulta de URL para que, una vez que el inicio de sesión sea exitoso, el usuario sea llevado directamente a donde originalmente intentaban ir.

Marco.b
fuente
1
¿Por qué se rechaza esta respuesta?
Miloš Kroulík
@ milos.kroulik, supongo porque la pregunta es sobre Drupal 8 pero ese módulo es para 7y6
M ama D
1
No, ese módulo tiene una versión de Drupal 8 en desarrollo
Colin Shipton
1
Estoy bastante seguro de que el voto negativo se debió a que la respuesta era una respuesta "solo de enlace" (una razón típica para que las respuestas se voten negativamente, o incluso se eliminen ...). Dichas respuestas también suelen aparecer en la cola de revisión de "respuestas de baja calidad" ... Consulte mi versión editada de esta respuesta ahora para obtener una versión mejorada de la misma (ya no corre el riesgo de ser considerada como una respuesta de solo enlace).
Pierre.Vriens
Esta respuesta no tiene en cuenta si el usuario ya ha iniciado sesión o si el sitio usa fast404 y 403.
0

(1) cree un nodo de página con un alias como "/my403.html"

(2) vaya a / admin / config / system / site-information y configure "/my403.html" como 403-Errorpage

(3) vaya a / admin / structure / block y agregue el bloque "User login" (Sec. Forms) a la región de contenido principal. Restrinja la apariencia del bloque a la página "my403.html" y al rol "invitado".

Eso es.

Si necesita más control, cree un controlador para su página 403 y agregue el UserLoginForm a mano.

Saludos cordiales, Rainer

Rainer Feike
fuente