Afgeschermde pagina's

Drupal 7, 8 en 9

Veel websites hebben een afgeschermd deel voor bijvoorbeeld leden, medewerkers, personeel, enzovoorts. Maar hoe zorg je er nu voor dat de pagina’s ook alleen te bezoeken zijn voor je eigen doelgroep en niet voor anderen? Hiervoor moeten enkele zaken geregeld worden, zoals het schrijven van een klein programma.

Wil je dat voor alle pagina’s ingelod is, kijk dan op de pagina „Login is verplicht” (alleen Drupal 9).

Ik zal hieronder ervan uitgaan dat de doelgroep „leden” is. Als de naam anders moet zijn, vervang dan hieronder „leden” door je eigen naam.

De beschreven programma’s sturen niet-ingelogde bezoekers die een pagina van een specifiek inhoudstype opvragen door naar de inlogpagina en vervolgens terug naar de oorspronkelijk opgevraagde pagina.
Tevens wordt als alternatief de wijziging opgegeven om de bezoeker van zo’n pagina door te sturen naar de voorpagina.

Wat moet je allemaal doen

1. Je moet op een of andere manier de doelgroep kunnen onderscheiden van andere bezoekers van de website. De meest eenvoudige manier (vanuit beveiligingsoogpunt) is de juiste mensen toegang te geven tot deze pagina’s middels een login.
Vanuit beheersoogpunt kan dit echter problemen geven (zoals tot wat heeft iedereen met een inlogcode toegang?, hoe verstrek ik iedereen een gebruikersnaam / wachtwoord?), maar daar gaat deze pagina niet over. Ook niet over welke rol(len) een lid kan hebben.

2. De speciale pagina’s voor de doelgroep moeten ook gekenmerkt worden. Dit is zeer simpel. Maak een nieuw inhoudstype aan: Structuur » Inhoudstypen » Inhoudstype toevoegen.

Geef deze een duidelijke naam, bijvoorbeeld: „Leden” en type „leden”. Zet in de beschrijving een toepasselijke tekst, zodat iedere beheerder weet waarvoor deze pagina bedoeld is.

3. Maak een module met als naam: leden_toegang. Deze module bestaat uit een map met de eigen naam (leden_toegang) en enkele bestanden.

Drupal 7

Voor Drupal 7 zijn dat twee bestanden: leden_toegang.info en leden_toegang.module. Het info bestand er als volgt uit:

name = Leden toegang
description = Bezoekers (niet ingelogd) die een pagina van het inhoudstype leden bezoeken worden automatisch naar de loginpagina geleid.
version = "7.x-1.0"
project = "leden_toegang"
core = 7.x

Het module bestand bestaat uit de volgende code:

<?php
function leden_toegang_node_view($node, $view_mode, $language) {
  // alleen toegang tot ledenpagina's voor ingelogde personen.
  if ($node->type == 'leden' && user_is_anonymous()
&& $view_mode != 'search_index') {
    drupal_goto('user/login', array('query' => drupal_get_destination()));
  }
}

We beginnen met het opgeven dat de module een PHP-script is. Hierin gebeurt het volgende: als het inhoudstype ($node→type) gelijk is aan leden, de bezoeker niet is ingelogd en de cron-job niet actief, dan wordt deze automatisch naar het inlogscherm doorgestuurd (instructiedeel: drupal_goto(‘user/login’,). Na het inloggen zal de medewerker automatisch de oorspronkelijk opgevraagde pagina te zien krijgen (instructiedeel: drupal_get_destination()).

Attentie: aan het eind van de module mag géén afsluitende „?>” staan ten teken dat het PHP-script ten einde is.

    Als je de bezoeker niet naar de inlogpagina wil verwijzen maar naar de voorpagina, gebruik dan: drupal_goto(”);

    Drupal 8 en 9

    Voor Drupal 8 en 9 bestaat de module uit vier bestanden: leden_toegang.info.yml, leden_toegang.services.yml, leden_toegang.module en LedenToegangRedirectSubscriber.php. De mapstructuur is ook anders dan in Drupal 7 en ziet er als volgt uit:

    leden_toegang
      leden_toegang.info.yml
      leden_toegang.services.yml
      leden_toegang.module
      src
        EventSubscriber
          LedenToegangRedirectSubscriber.php

    Het info bestand er als volgt uit:

    name: Leden toegang
    description: Leden toegang module
    type: module
    core_version_requirement: ^8.8 || ^9
    package: Leden

    Het services bestand:

    services:
      services: leden_toegang.redirect_subscriber:

        class: \Drupal\leden_toegang\EventSubscriber\LedenToegangRedirectSubscriber
        arguments: ['@current_user', '@current_route_match']
        tags:
          - { name: event_subscriber, priority: 100 }

    Het module bestand:

    <?php

    /**
     * @file
     * Leden toegang module file.
     */

    use Drupal\Core\Routing\RouteMatchInterface;

    /**
     * Implements hook_help().
     */
    function leden_toegang_help($route_name, RouteMatchInterface $route_match) {
      switch ($route_name) {
        case 'help.page.leden_toegang':
          $output = '<h3>' . t('About') . '</h3>';
          $output .= '<p>Redirect naar login voor toegang tot ledenpagina.</p>';
          return $output;

        default:
      }
    }

    en het LedenToegangRedirectSubscriber bestand:

    <?php
     
    namespace Drupal\leden_toegang\EventSubscriber;
     
    use Drupal\Core\Routing\RedirectDestinationTrait;
    use Drupal\Core\Routing\LocalRedirectResponse;
    use Drupal\Core\Routing\RouteMatchInterface;
    use Drupal\Core\Session\AccountProxyInterface;
    use Drupal\Core\Url;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\HttpKernel\Event\GetResponseEvent;
    use Symfony\Component\HttpKernel\KernelEvents;
     
    /**
     * Event subscriber om door te schakelen naar de login pagina.
     *
     * Bezoekers (niet ingelogd) die een pagina met inhoudstype leden bezoeken
     * worden automatisch naar de loginpagina geleid.
     */
    class LedenToegangRedirectSubscriber implements EventSubscriberInterface {
      use RedirectDestinationTrait;
     
      /**
       * De huidige user.
       *
       * @var \Drupal\Core\Session\AccountProxyInterface
       */
      protected $huidigeUser;
     
      /**
       * De huidige route match.
       *
       * @var \Drupal\Core\Routing\RouteMatchInterface
       */
        protected $huidigeRouteMatch;
     
      /**
       * LedenToegangRedirectSubscriber constructor.
       *
       * @param \Drupal\Core\Session\AccountProxyInterface $huidigeUser
       *   De huidige user.
       * @param \Drupal\Core\Routing\RouteMatchInterface $huidigeRouteMatch
       *   De huidige route match.
       */
      public function __construct(AccountProxyInterface $huidigeUser, RouteMatchInterface $huidigeRouteMatch) {
        $this->currentUser = $huidigeUser;
        $this->currentRouteMatch = $huidigeRouteMatch;
      }
     
      /**
       * {@inheritdoc}
       */
      public static function getSubscribedEvents() {
        $events[KernelEvents::REQUEST][] = ['RequiredLogin', 0];
        return $events;
      }
     
      /**
       * Handler voor het kernel request event.
       *
       * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
       *   Het event.
       */
      public function RequiredLogin(GetResponseEvent $event) {
        // Al ingelogd? Dan klaar.
        if ($this->currentUser->isAuthenticated()) {
          return;
        }
     
        // Is het geen node? Dan klaar.
        $node = $this->currentRouteMatch->getParameter('node');
        if (!($node instanceof \Drupal\node\NodeInterface)) {
          return;
        }
     
        // Test op juiste bundle = inhoudstype (nodetype).
        // Attentie: gebruik de machine-naam van het nodetype!
        if ($node->bundle() != 'leden') {
          return;
        }
     
        // Status: bezoeker niet ingelogd, mag dit nodetype zo niet bekijken.
        // Redirect naar inlogscherm en daarna terug naar de gewenste pagina.
        // Attentie: via de routing.yml van de user module wordt de url opgehaald!
        // Daarom staat er NIET: internal:/user/login maar WEL user.login.
        $url = Url::fromRoute('user.login', [], ['query' => $this->getDestinationArray()]);
        $event->setResponse(new LocalRedirectResponse($url->toString()));
      }
    }

    Voor oudere versies van Drupal 8 moeten mogelijk de use statements:

    use Drupal\Core\Routing\RedirectDestinationTrait;
    use Drupal\Core\Routing\LocalRedirectResponse;
    use Drupal\Core\Routing\RouteMatchInterface;
    use Drupal\Core\Session\AccountProxyInterface;
    use Drupal\Core\Url;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\HttpKernel\Event\GetResponseEvent;
    use Symfony\Component\HttpKernel\KernelEvents;

    vervangen worden door:

    use Drupal\Core\Routing\RedirectDestinationTrait;
    use Drupal\Core\Routing\CurrentRouteMatch;
    use Drupal\Core\Routing\LocalRedirectResponse;
    use Symfony\Component\HttpKernel\KernelEvents;
    use Drupal\Core\Session\AccountProxyInterface;
    use Drupal\Core\Url;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\HttpKernel\Event\GetResponseEvent;

    Als, net als in het voorbeeld voor Drupal 7 de bedoeling is om niet-ingelogde bezoekers die pagina’s met inhoudstype „Leden” opvragen door te sturen naar de voorpagina, dan zijn er kleine wijzigingen nodig:

    • use Drupal\Core\Routing\RedirectDestinationTrait; kan vervallen
    • use RedirectDestinationTrait; (onder class LedenToegangRedirectSubscriber) kan ook vervallen
    • vervang onderaan
      $url = Url::fromRoute(‘user.login’, [], [‘query’ ⇒ $this→getDestinationArray()]);
      door: $url = Url::fromUri(‘internal:/’);.

    Vervolg algemene aanwijzingen

    4. Installeer deze module net als alle andere modules in je website en activeer deze.

    5. Maak nu nieuwe pagina’s voor de leden aan met het inhoudstype „Leden”.

    6. De pagina’s moeten waarschijnlijk in het menu worden opgenomen, maar niet zichtbaar zijn voor gewone bezoekers. Maak een nieuw menu aan: Structuur » Menu’s » Menu toevoegen
    met als naam Leden. Zet alle speciale pagina’s in dit menu.

    Hiervoor kan ook het gebruikersmenu worden gebruikt.

    7. Ga nu naar Blokken: Structuur » Blokken
    en schakel het menu in. Klik daarna op „instellen” naast de naam van dit blok en vink bij „Inhoudstypen” het inhoudstype „Leden” en sla dit blok op. Het menu is alleen te zien als een pagina’s van dit inhoudstype wordt opgevraagd en in dit menu staat.

    8. Om te voorkomen dat bezoekers het bestaan van de node kunnen achterhalen moet de node niet getoond worden via de zoekmachine. Gebruik hiervoor de module search_restrict (D7) of search_exclude (D8 en D9).

    9. Als je module XML Sitemap, Simple XML sitemap of een andere sitemapprogramma gebruikt, denk er dan aan om bij de instellingen van het nieuwe inhoudstype op te geven dat de pagina niet in de sitemap opgenomen mag worden!