Como redirecionar um usuário anônimo para o formulário de logon após um erro 403?

13

Desejo redirecionar um usuário anônimo para o formulário de logon se esse usuário encontrar um erro 403.

Criei um assinante de evento e esse é o meu código, mas acabo em loop na página atual.

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

Eu acho que isso está relacionado ao fato de que a resposta já contém destination (uri atual) e system.404 e system.403 têm alguma alta prioridade que me impede de substituir isso.

Pierre.Vriens
fonte
Você pode adicionar toda a classe em vez do método?
googletorp
Existem apenas $ events [KernelEvents :: REQUEST] = 'checkLoginNeeded'; no método getSubscribEvents ().

Respostas:

13

A maneira mais fácil é procurar /admin/config/system/site-informatione preencher o campo que lê Default 403 (access denied) pagecomuser/login

Kartagis
fonte
7
Essa é uma boa solução, mas não leva em conta o fato de que o usuário já pode estar logado, como mencionei na descrição.
13

Vi que essa pergunta nunca foi respondida como fazer isso programaticamente. O código realmente funciona, quando colocado em um Assinante de exceção:

/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
fonte
4
Isso funciona e é provavelmente a melhor resposta até que os módulos relevantes (regras incluídas) tenham versões estáveis. Eu tive que adicionar -> toString () para $ query [ 'destino'] = Url :: fromRoute ( '<atual>') para chegar a este trabalho
Colin Shipton
2
Esta resposta merece aparecer mais!
pbonnefoi 30/01/19
9

Olhando apenas o título desta pergunta (= Como redirecionar o usuário para o formulário de login do 403? ), Existem 2 opções para fazer isso, sem nenhum código personalizado envolvido, conforme detalhado abaixo.

Opção 1: Use o módulo CustomError

O módulo CustomError permite que o administrador do site crie páginas de erro personalizadas para os códigos de status HTTP 403 (acesso negado) e 404 (não encontrado), sem criar nós para cada um deles. Mais alguns detalhes sobre seus recursos (na página do projeto):

  • Título da página configurável e descrições.
  • Não há cabeçalhos de autor e data / hora, como nos nós normais.
  • Qualquer texto formatado em HTML pode ser inserido no corpo da página.
  • As páginas de erro são permitidas.
  • Os usuários que não estão conectados e tentam acessar uma área que requer login serão redirecionados para a página que estavam tentando acessar após o login.
  • Permite redirecionamentos personalizados para 404s.

Você provavelmente se interessará principalmente pela parte sobre " Os usuários que não estiverem conectados e tentarem acessar uma área que requer login serão redirecionados para a página que estavam tentando acessar após o login ".

Para o D8, também está disponível uma versão 8.x-1.x-dev para este módulo, mais detalhes sobre ele podem ser encontrados na edição # 2219227 .

Opção 2: Use o módulo Regras

Suponha que o caminho da página "Padrão 403" esteja definido como no_access(via admin). Em seguida, crie uma regra usando o módulo Regras , com como Evento algo como "Depois de visitar o nó no_access". Para que toda a regra fique assim:

  • Eventos: Após visitar o nóno_access
  • Condições:

    1. O usuário tem funções -Parameter: User: [site:current-user], Roles: anonymous user
    2. NÃO Comparação de texto -Parameter: Text: [site:current-page:url], Matching text: user/login
  • Ações: redirecionamento de página -Parameter: URL: user/login

Caso deseje fazer isso, você pode adicionar outra Ação para também exibir alguma mensagem (informativa) na área de mensagens do Drupal, com algo como "Você tentou visitar uma página para a qual o login é necessário ...".

É verdade que pode ser necessário ativar um módulo contribuído extra ( Regras ). Mas, como indicado por sua crescente popularidade também, esse módulo provavelmente já está ativado em praticamente qualquer site (semelhante ao módulo Views ), porque existem dezenas de casos de uso para este módulo.

Para o D8, também está disponível uma versão 8.x-3.x-alfa1 para este módulo, mais detalhes sobre a versão D8 podem ser encontrados na edição nº 2574691 , que inclui um link para o problema das regras " Regras 8.x Roteiro "

Se o acima exposto não ajudar, verifique se o motivo do seu loop (ou "alguma prioridade alta", como na sua pergunta) não pode ser evitado / explicado por algo semelhante à resposta à pergunta " Como especificar um evento de regras como "O conteúdo será visualizado"? ".

Pierre.Vriens
fonte
4

Eu acho que a solução para o seu problema é simples. Você pode criar facilmente uma página personalizada 404e 403, dentro desta página, redirecionar usuários anônimos para a /userpágina.

Você pode 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';
   }
}

Sempre que ocorrer 404, você page--404.tpl.phpserá usado. Nesta página, use este código

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

A página Como criar 403 e 404 personalizadas no Drupal explica outro método de criação de uma página para 403e 404.

M ama D
fonte
5
Ei, cara, você deve verificar as tags e o código. Esse cara é claramente usando Drupal 8.
alexej_d
1
oi, eu dei a ele o algoritmo, ele pode facilmente alterá-lo para o 8formato #
M ama D
3

A maneira mais fácil de fazer isso é usar o módulo Redirecionar 403 para login do usuário (existe uma versão de desenvolvimento para o D8). Aqui está uma citação sobre ele (na página do projeto):

Redirecione a página de erro HTTP 403 para a página Drupal / user / login com uma mensagem opcional que diz:

"Acesso negado! Você deve fazer login para visualizar esta página."

Além disso, a página desejada é anexada à string de consulta do URL, para que, assim que o login seja bem-sucedido, o usuário seja levado diretamente para onde estava originalmente tentando ir.

Marco.b
fonte
1
Por que esta resposta foi reduzida?
Miloš Kroulík
@ milos.kroulik Acho que é porque a pergunta é sobre Drupal 8, mas esse módulo é para 7e6
M ama D
1
Sem esse módulo tem uma versão Drupal 8 em desenvolvimento
Colin Shipton
1
Certeza de que o voto negativo foi devido à resposta ser uma resposta "somente link" (uma razão típica para as respostas serem votadas negativamente ou mesmo excluídas ...). Essas respostas também costumam aparecer na fila de revisão "respostas de baixa quaidade" ... Consulte a minha versão editada desta resposta agora para obter uma versão aprimorada (não corre mais o risco de ser considerada uma resposta apenas de link).
Pierre.Vriens
Essa resposta não leva em conta se o usuário já está conectado ou se o site está usando fast404 e 403.
0

(1) crie um nó da página com um alias como "/my403.html"

(2) vá para / admin / config / system / site-information e defina "/my403.html" como 403-Errorpage

(3) vá para / admin / structure / block e adicione o bloco "Login de usuário" (Sec. Forms) à região de conteúdo principal. Restrinja a aparência do bloco à página "my403.html" e à função "convidado".

É isso aí.

Se você precisar de mais controle, crie um controlador para sua página 403 e adicione o UserLoginForm manualmente.

Atenciosamente, Rainer

Rainer Feike
fonte