logo

Extra Block Types (EBT) - Nuova esperienza con Layout Builder❗

Extra Block Types (EBT) - tipi di blocchi stilizzati e personalizzabili: Slideshows, Tabs, Cards, Accordion e molti altri. Impostazioni integrate per sfondo, DOM Box, plugin javascript. Vivi oggi il futuro della costruzione dei layout.

Demo moduli EBT Scarica moduli EBT

❗Extra Paragraph Types (EPT) - Nuova esperienza con Paragraphs

Extra Paragraph Types (EPT) - insieme di moduli basati su paragrafi in modo analogo.

Demo moduli EPT Scarica moduli EPT

Scorri

Limitare l'accesso al vocabolario dei termini di tassonomia utilizzando un Event Subscriber

02/09/2025, by Ivan

Menu

A volte hai bisogno di Categorie fisse e permanenti sul sito, che non dovrebbero essere modificate accidentalmente. In questo caso puoi utilizzare del codice personalizzato con un Event Subscriber.

Aggiungiamo una nuova classe Event Subscriber in un modulo personalizzato.

drupalbook_custom.services.yml

services:  
  drupalbook_custom.tag_redirect_subscriber:
    class: Drupal\drupalbook_custom\EventSubscriber\TagRedirectSubscriber
    arguments:
      - '@entity_type.manager'
      - '@current_user'
    tags:
      - { name: event_subscriber }

Includiamo poi il nostro Event Subscriber in drupalbook_custom/src/EventSubscriber/TagRedirectSubscriber:

<?php

namespace Drupal\drupalbook_custom\EventSubscriber;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Reindirizza gli utenti non amministratori dalle pagine di amministrazione del vocabolario Tag.
 *
 * Un subscriber a livello di Request viene eseguito precocemente, permettendoci di interrompere
 * la richiesta e restituire una risposta di redirect prima che venga eseguito il controller.
 */
class TagRedirectSubscriber implements EventSubscriberInterface {

  /**
   * Il servizio entity-type manager.
   *
   * Mantenuto come dipendenza d'esempio; non è strettamente richiesto dalla logica attuale,
   * ma utile se in futuro si necessitano caricamenti di entità.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * Il servizio proxy dell'utente corrente.
   *
   * Utilizzato per controlli rapidi sui ruoli per bypassare il redirect
   * per gli amministratori.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected AccountProxyInterface $currentUser;

  /**
   * Costruisce il subscriber.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   L'entity-type manager.
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
   *   L'utente che effettua la richiesta.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    AccountProxyInterface $current_user,
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->currentUser = $current_user;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    // Priorità 32 per garantire che i parametri della route siano disponibili,
    // ma il controller non sia ancora stato eseguito.
    return [
      KernelEvents::REQUEST => ['onKernelRequest', 32],
    ];
  }

  /**
   * Esegue il redirect quando un non-amministratore accede alle route admin del vocabolario Tag.
   *
   * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
   *   L'evento kernel con la richiesta.
   */
  public function onKernelRequest(RequestEvent $event): void {
    // Agisce solo sulla richiesta principale.
    if (!$event->isMainRequest()) {
      return;
    }

    // Permette agli amministratori di procedere.
    if ($this->currentUser->hasRole('administrator')) {
      return;
    }

    $request = $event->getRequest();
    $route_name = $request->attributes->get('_route');

    // Destinazione per tutti i tentativi bloccati.
    $redirect_to = 'https://drupalbook.org/admin/structure'
      . '/taxonomy/manage/tag/overview';

    switch ($route_name) {
      case 'entity.taxonomy_vocabulary.overview_form':
      case 'entity.taxonomy_vocabulary.overview_terms':
      case 'entity.taxonomy_term.add_form':
        // Controlla che si stia operando sul vocabolario "tag".
        $vocabulary = $request->attributes->get('taxonomy_vocabulary');
        if (!empty($vocabulary) && $vocabulary->id() === 'tag') {
          $event->setResponse(new TrustedRedirectResponse($redirect_to));
        }
        return;

      case 'entity.taxonomy_term.edit_form':
      case 'entity.taxonomy_term.delete_form':
        /** @var \Drupal\taxonomy\Entity\Term|null $term */
        $term = $request->attributes->get('taxonomy_term');
        // bundle() restituisce il nome macchina del vocabolario.
        if ($term && $term->bundle() === 'tag') {
          $event->setResponse(new TrustedRedirectResponse($redirect_to));
        }
        return;

      default:
        return;
    }
  }

}

La classe TagRedirectSubscriber è un Event Subscriber personalizzato per Drupal, progettato per limitare l'accesso alle pagine di amministrazione di un vocabolario di tassonomia specifico (in questo caso, "tag") agli utenti non amministratori. Ecco un riepilogo della sua struttura e degli aspetti principali presenti nel codice:

1. Scopo e Caso d'Uso

  • Obiettivo: Evitare aggiornamenti accidentali o non autorizzati al vocabolario "tag" reindirizzando gli utenti non amministratori lontano dalle route amministrative.
  • Beneficio: Fornisce un livello di controllo UI/UX sugli accessi per tassonomie critiche, mantenendo stabili le categorie fisse.

2. Struttura della Classe e Dipendenze

  • La classe implementa EventSubscriberInterface, rendendola compatibile con il sistema eventi di Symfony usato da Drupal.
  • Dipendenze iniettate via costruttore:
    • EntityTypeManagerInterface: incluso per possibili operazioni future sulle entità. Non necessario nella logica attuale, ma utile per estensioni.
    • AccountProxyInterface: usato per ottenere e verificare i ruoli dell'utente corrente.
    L’iniezione di dipendenze garantisce che il subscriber sia testabile, riutilizzabile e conforme alle best practice del container di servizi Drupal.

3. Eventi Sottoscritti

  • La classe sottoscrive l’evento KernelEvents::REQUEST con una priorità di 32.
    Questa priorità garantisce:
    • La disponibilità dei parametri di route (routing già risolto).
    • Il controller non ancora eseguito, permettendo al subscriber di intercettare e restituire un redirect.

4. Logica di Redirect

  • Il metodo onKernelRequest() gestisce controlli di accesso e redirect:
    • Agisce solo sulle richieste principali: evita esecuzioni multiple su sub-request.
    • Permette gli amministratori: l'utente con ruolo administrator passa sempre.
    • Controlla i nomi delle route: agisce solo su route legate alla tassonomia o ai suoi termini.
    • Reindirizza i non-amministratori:
      • Per overview, aggiunta o lista (entity.taxonomy_vocabulary.overview_form, entity.taxonomy_vocabulary.overview_terms, entity.taxonomy_term.add_form), verifica che il vocabolario sia tag.
      • Per modifica e cancellazione (entity.taxonomy_term.edit_form, entity.taxonomy_term.delete_form), verifica che il bundle() del termine sia tag.
    • Usa un trusted redirect: se le condizioni corrispondono, l’utente viene reindirizzato a una pagina admin sicura del vocabolario "tag".
  • Estendibilità: la logica è facilmente estendibile per altri vocabolari o ruoli semplicemente modificando le condizioni.

5. Sicurezza e Best Practice

  • Intercettazione precoce: Eseguito all'inizio della richiesta, il subscriber può impedire accessi prima che vengano caricati o mostrati dati sensibili.
  • Bypass basato sui ruoli: Controlla rapidamente i ruoli degli utenti per non ostacolare gli admin.
  • Chiara separazione delle responsabilità: La logica di routing, i controlli utente e il redirect sono ben separati e manutenibili.

6. Potenziali Miglioramenti

  • Poiché viene iniettato EntityTypeManagerInterface, è facile aggiungere in futuro controlli sulle entità (es. permessi basati su proprietà del termine o contenuti correlati).
  • È possibile generalizzare la classe per gestire più vocabolari o reindirizzamenti configurabili via interfaccia.

7. Conclusioni Chiave

  • Questo Event Subscriber mostra un approccio pratico per il controllo degli accessi in Drupal, sfruttando l’architettura ad eventi di Symfony per un’intercettazione rapida ed efficiente delle richieste.
  • L’approccio è ideale per proteggere i vocabolari di tassonomia che dovrebbero essere gestiti solo da utenti fidati, riducendo il rischio di modifiche accidentali.