Documentatie voor klanten en partners van Digitaal Vlaanderen - bouwstenen Mijn Burgerprofiel, Verenigingsloket en e-loketondernemers">Documentatie voor klanten en partners van Digitaal Vlaanderen - bouwstenen Mijn Burgerprofiel, Verenigingsloket en e-loketondernemers


Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 13 Next »

Eenvoudig vs. gekoppeld toegangsbeheer

De global header integreren op een gastwebsite kan op de volgende 2 manieren:

Ook bij een global header met eenvoudig toegangsbeheer is de link naar het e-loket ondernemers en het Verenigingsloket beschikbaar.

  • Met gekoppeld toegangsbeheer: gebruikers kunnen meteen aanmelden in verschillende hoedanigheden via ACM/IDM, bijv. als burger, als ambtenaar en/of als economische actor. De gastwebsite moet hiervoor de hoedanigheidswissel expliciet toevoegen. Het openen van het pad dat bij die wissel hoort (switchCapacityUrl), start de flow voor gericht aanmelden.

 

 

Om gericht te kunnen aanmelden en de gebruiker de keuze te geven tussen meerdere hoedanigheden, moet Toegangsbeheer (ACM) eerst valideren dat de gevraagde identiteit een toegelaten identiteit is. Zie ook de ACM-technische informatie “Gericht aanmelden”. De hoedanigheid zelf wordt bepaald in de ACM-schermen. De global header reageert op basis van de informatie in de ACM-schermen.

Zie ook:

Integratie van de global header met eenvoudig toegangsbeheer (ACM)

Voor elke gastwebsite die de global header aanbiedt, moet er een integratie bestaan die de activiteit van de burger met de global header meldt aan de header. Hiervoor moet er minimaal eenvoudig toegangsbeheer (AuthentiCation Management of ACM) aanwezig zijn zodat:

  • de gebruiker zich kan aanmelden

  • het gedrag tussen de website en de global header consistent blijft

Voor meer informatie over een koppeling met ACM, zie https://www.vlaanderen.be/acm-idm-standaard-aansluitingsproces .

Start de koppeling met de global header en kies in het formulier voor eenvoudig toegangsbeheer.

Integratie van de global header met gekoppeld toegangsbeheer (ACM + Single Sign-on)

Naast de algemene integratieregels, die van toepassing zijn voor elke website, bestaan er ook een aantal extra vereisten voor websites met gekoppeld toegangsbeheer.

  • Activiteitstracking

  • De status van de sessie rapporteren

  • De aanvragen voor applicatie logout afhandelen

  • Login en Logout endpoint

Start de koppeling met de global header en kies in het formulier voor gekoppeld toegangsbeheer.

Activiteitstracking

Met activiteitstracking wordt nagegaan of een gebruiker actief is met de global header. Bij inactiviteit van 20 minuten wordt de gebruiker automatisch afgemeld.

Om de activiteitstracking voor een webpagina correct te laten werken, moet de extensie op de hoogte blijven van activiteit op de webpagina. In het onderstaande codevoorbeeld staat een eenvoudige manier om activiteit van een gebruiker te detecteren en te rapporteren aan de extensie.

// Capture any widget that is present or will be present on the webpage.
vl.widget.client.capture(function (widget) {
  // Only process the widget if widget is a global header.
  if (widget.getPluginTypeId() === 'global_header') {
    // Get the Citizen Profile Session extension from the global header widget.
    widget.getExtension('citizen_profile.session').then(function (session) {
      
      /**
       * Event handler which extends a Citizen Profile session.
       */
      function activityEventHandler() {
        // Inform the Citizen Profile Session extension about activity.
        session.extend();
      }

      // Build a list of event names which should be used for activity tracking.
      var eventNames = [
        'mousedown', 
        'mousemove', 
        'mousewheel', 
        'DOMMouseScroll', 
        'scroll', 
         'wheel', 
         'keydown', 
         'keypress', 
         'touchmove', 
         'touchstart'
      ];
      // Iterate through the events names.
      for (var i = 0; i < eventNames.length; i++) {
        // Register our event handler given event name.
        window.addEventListener(eventNames[i], activityEventHandler);
      }
    });
  }
});

Het is niet nodig om de event handler van throttling te voorzien. Dit wordt door de Burgerprofiel-extensie voorzien bij de oproep van "session.extend()".

Activiteit tracken voor websites met ACM

Elke website moet activiteit tracken. Maar websites met SSO-ondersteuning (en ACM) hebben een aantal bijkomende vereisten voor veiligheid en integratie, zoals getoond in de onderstaande voorbeelden:

De status van de sessie rapporteren
// Capture any widget that is present or will be present on the webpage.
vl.widget.client.capture(function (widget) {
  // Only process the widget if widget is a global header.
  if (widget.getPluginTypeId() === 'global_header') {
    // Get the Citizen Profile Session extension from the global header widget.
    widget.getExtension('citizen_profile.session').then(function (session) {
      // This variable is purely to indicate which values are allowed (true / false).
      var websiteHasAuthenticatedSession = false;
      // Inform the session extension about the current session state of the website.
      session.configure({
        active: websiteHasAuthenticatedSession,
        endpoints: {
          loginUrl: '/login',
          loginRedirectUrl: '/profile',
          logoutUrl: '/logout'
        }
      });
    });
  }
});

Gedurende de life cycle van een pagina kan de configure-methode maar één keer worden opgeroepen. Alle volgende oproepen resulteren in een foutmelding.

Als de aanmeldstatus op de gastwebsite moet wijzigen, moet de logout-methode worden opgeroepen zodat de nodige flows gestart worden om correct af te melden.

De endpoints overschrijven

De standaard login/logout-endpoints kunnen altijd overschreven worden door een eigenschap toe te voegen aan het object in de configure-methode. Het codevoorbeeld hieronder toont hoe de endpoints te overschrijven en een lokale ontwikkeling mogelijk te maken. Een concreet voorbeeld is het hergebruik van de header voor verschillende loketfuncties. De endpoints mogen ook een relatief pad gebruiken t.o.v. de documentroot.

// Capture any widget that is present or will be present on the webpage.
vl.widget.client.capture(function (widget) {
  // Only process the widget if widget is a global header.
 if (widget.getPluginTypeId() === 'global_header') {
    // Get the Citizen Profile Session extension from the global header widget.
    widget.getExtension('citizen_profile.session').then(function (session) {
      // This variable is purely to indicate which values are allowed (true / false).
      var websiteHasAuthenticatedSession = false;
      // Inform the session extension about the current session state of the website. Keep in mind
      // this operation can only be performed once on every page load.
      session.configure({
        active: websiteHasAuthenticatedSession,
        endpoints: {
          loginUrl: '/login',
          loginRedirectUrl: '/profile',
          logoutUrl: '/logout'
        }
      });
     });
    }
  });
De sessie verlengen op basis van activiteit
// Capture any widget that is present or will be present on the webpage.
vl.widget.client.capture(function (widget) {
  // Only process the widget if widget is a global header.
  if (widget.getPluginTypeId() === 'global_header') {
    // Register for session extend event.
    widget.on('citizen_profile.session.extend', function (event) {
      // Perform custom website specific session extend logic.
      console.debug('Received session extend request');
    }); 
  }
});

De gastwebsite informeert ook over activiteit en kan op basis daarvan de eigen sessie verlengen. Dit is alleen van toepassing als de gastwebsite zelf de maximumduur van een sessie beperkt.

De aanvragen voor applicatie-logout afhandelen via JavaScript

// Capture any widget that is present or will be present on the webpage.
vl.widget.client.capture(function (widget) {
  // Only process the widget if widget is a global header.
  if (widget.getPluginTypeId() === 'global_header') {
    // Get the Citizen Profile Session extension from the global header widget.
    widget.on('citizen_profile.session.logout.request', function (logoutRequest) {
      // Acknowledge the logout request to prevent the session extension from performing default
      // action due to response timeout (5 seconds).
      logoutRequest.acknowledge();

      // Evaluate the type of logout request.
      switch (logoutRequest.getRequest().getReason()) (
        // Logout was requested because the citizen profile extension has detected an expired
        // session which prevents the user from accessing citizen profile without a step-up.
        // This could be the result of an application logout or external logout.
        case 'expired':
          // Validate whether our application still has a valid session. Keep in mind that this 
          // implementation is purely as an example and does not enforce any rules on how a session
          // state is detected. In our example the API call will return 204 if session is present,
          // otherwise 401.
          fetch('http://localhost/api/v1/session/validate')
            .then(function (response) {
              // Check whether the application backend reported an active session.
              if (response.status === 204) {
                // Reject the logout request as our application still has an active session.
                logoutRequest.reject();
              }
              else {
                // Accept the logout request as our application has no active session or failed to
                // generate a valid response.
                logoutRequest.accept();
              }
            })
            .catch(function () {
              // Failed to determine the session state accept the request to ensure no session
              // inconsistency.
              logoutRequest.accept();
            });
          break;

        // Logout was requested by the user. This request should never be rejected in normal
        // circumstances.
        case 'user':
        // Logout was requested as the citizen profile extension has detected inactivity from
        // the user.
        case 'inactivity':
          // Accept the request for website logout.
          logoutRequest.accept();
          break;

        default:
          // Reject the request for website logout.
          logoutRequest.reject();
          break;
      }
    }); 
  }
});

Aanmelden

Om de Mijn Burgerprofiel-extensie een login te laten uitvoeren voor een website, moet de login-URL, die de aanmeldflow kan starten, beschikbaar zijn. De modal met aanmeldopties is de start van die aanmeldflow.

Zo lang de gebruiker niet is aangemeld, blijft het beletselteken rechts bovenaan actief.

Zodra de gebruiker is aangemeld, moet de callback-pagina van de gastwebsite een bericht verzenden met daarin de status van het aanmelden: gelukt of mislukt.

Aanmelden succesvol afgehandeld

// Serialize the login complete message.
var message = JSON.stringify({
  type: 'vl.widget.global_header.citizen_profile.session.login.complete'
});
// Notify the top most window about our login progress.
window.top.postMessage(message, '*');

Als de website een succesvolle aanmeldflow doorloopt, redirect de Burgerprofiel-extensie automatisch naar de geconfigureerde LoginRedirectUrl, zoals meegegeven bij het rapporteren over de status van de websitesessie:

// Capture any widget that is present or will be present on the webpage.
vl.widget.client.capture(function (widget) {
  // Only process the widget if widget is a global header.
  if (widget.getPluginTypeId() === 'global_header') {
    // Get the Citizen Profile Session extension from the global header widget.
    widget.getExtension('citizen_profile.session').then(function (session) {
      // This variable is purely to indicate which values are allowed (true / false).
      var websiteHasAuthenticatedSession = false;
      // Inform the session extension about the current session state of the website.
      session.configure({
        active: websiteHasAuthenticatedSession,
        endpoints: {
          loginUrl: '/login',
          loginRedirectUrl: '/profile',
          logoutUrl: '/logout',
          // Pad welke volgende specificatie implementeert:
          // https://authenticatie.vlaanderen.be/docs/beveiligen-van-toepassingen/integratie-methoden/oidc/technische-info/gericht-aanmelden/
          switchCapacityUrl: '/wisselen-van-account'
        }
      });
    });
  }
});

De loginRedirectUrl verwijst naar de landingspagina waar standaard aangemelde gebruikers op moeten terechtkomen. In veel gevallen is dat de startpagina of bijv. /profile, /login, /...

Het is niet aangewezen om de loginRedirectUrl te gebruiken zolang de modal (scherm met de verschillende aanmeldmogelijkheden) is uitgeschakeld.

Voor meer informatie over rapporteren van de website sessiestatus, zie https://vlaamseoverheid.atlassian.net/wiki/spaces/IKPubliek/pages/2327449182/Technische+documentatie+Widget-platform#Activiteit-tracken-voor-websites-met-ACM-ondersteuning

Aanmelden mislukt

Als de aanmeldflow een fout genereert, geef dan in de onderstaande code een foutboodschap mee.

// Serialize the login failed message.
var message = JSON.stringify({
  type: 'vl.widget.global_header.citizen_profile.session.login.failure',
  // Optional, human readable message about the reason of failure.
  message: '<human readable error message>'
});
// Notify the top most window about our login progress.
window.top.postMessage(message, '*');

Afmelden

Om de Mijn Burgerprofiel-extensie een afmelding te laten uitvoeren voor een website, moet de logout-URL, die de logout-flow kan starten, beschikbaar zijn. Wanneer een gebruiker op Afmelden klikt, gebeurt er automatisch een redirect naar de logout-URL, zoals geconfigureerd bij de endpoints.

Optioneel kan hiervoor ook een event worden gebruikt: de logout.request geeft de acknowledge callback mee en vervangt dan het standaard redirect gedrag.

Fallback door featuredetectie

De login- en logout-URL's van de Mijn Burgerprofiel-extensie zorgen dus voor het aan- en afmelden vanuit de global header door de nodige informatie op te vragen via de ACM-integratie. Maar wanneer de global header uitzonderlijk niet beschikbaar is, bijvoorbeeld omdat het Widget-platform niet actief is, is het aangeraden om de Burgerprofiel-feature detectie uit te voeren.

Het onderstaande voorbeeld toont een combinatie van de status detecteren van de Mijn Burgerprofiel-sessie met die featuredetectie.

Dit codevoorbeeld is een richtlijn.

<!DOCTYPE html>
<html>
  <head>
    ...
  </head>
  <body>
    ... 
    <a id="login-button" href="/login">Login</a>
    <a id="logout-button" href="/logout">Logout</a>
    ...
    <script type="text/javascript">
      // Capture any widget that is present or will be present on the webpage.
      vl.widget.client.capture(function (widget) {
        // Only process the widget if widget is a global header.
        if (widget.getPluginTypeId() === 'global_header') {
          // Get the Citizen Profile Session extension from the global header widget.
          widget.getExtension('citizen_profile.session').then(function (session) {
            // Ensure the fallback login button uses the session instead of redirect to login page.
            document.getElementById('login-button').addEventListener('click', function (event) {
              // Start the login flow using the Citizen Profile Session extension.
              session.login();
              // Prevent default behavior as the redirect is no longer required.
              event.preventDefault();
            });

            // Ensure the fallback logout button uses the session instead of redirect to
            // logout page.
            document.getElementById('logout-button').addEventListener('click', function (event) {
              // Start the logout flow using the Citizen Profile Session extension.
              session.logout();
              // Prevent default behavior as the redirect is no longer required.
              event.preventDefault();
            });

            // This variable is purely to indicate which values are allowed (true / false).
            var websiteHasAuthenticatedSession = false;
            // Inform the session extension about the current session state of the website. Keep in mind
            // this operation can only be performed once on every page load.
            session.configure({ active: websiteHasAuthenticatedSession });
          });
        }
      });
    </script>
  </body>
</html>

Fallback in SSO-callbackpagina

De featuredetectie is voldoende voor de Mijn Burgerprofiel-extensie om de aanmeld- en afmeldflows te starten.

De enige uitzondering hierop is de callback-pagina die wordt opgeroepen door ACM (Toegangsbeheer). Standaard verzendt deze pagina een melding naar de Mijn Burgerprofiel-extensie om de modal te sluiten. Maar in het fallback scenario is er geen Burgerprofiel-extensie beschikbaar en zal de pagina niet opgeroepen worden vanuit de modal. Hierdoor is een extra controle nodig om een iframe te detecteren. Als er geen iframe beschikbaar is, moet de redirect manueel worden uitgevoerd; zowel bij een geslaagde als een gefaalde aanmelding.

In het onderstaande codevoorbeeld is de aanmelding geslaagd.

<!DOCTYPE html>
<html>
  <head>
    ...
  </head>
  <body>
    ...
    <script type="text/javascript">
      // Serialize the login complete message.
      var message = JSON.stringify({
        type: 'vl.widget.global_header.citizen_profile.session.login.complete'
      });
      // Notify the top most window about our login progress.
      window.top.postMessage(message, '*');

      // Check whether the page is being displayed without iframe.
      if (window.top === window) {
        // Manually redirect the browser to the authenticated page.
        window.location.replace('http://localhost/some-authenticated-homepage');
      }

      // Capture any widget that is present or will be present on the webpage.
      vl.widget.client.capture(function (widget) {
        // Only process the widget if widget is a global header.
        if (widget.getPluginTypeId() === 'global_header') {
          // Get the Citizen Profile Session extension from the global header widget.
          widget.getExtension('citizen_profile.session').then(function (session) {
            // Ensure the fallback login button uses the session instead of redirect to login page.
            document.getElementById('login-button').addEventListener('click', function (event) {
              // Start the login flow using the Citizen Profile Session extension.
              session.login();
              // Prevent default behavior as the redirect is no longer required.
              event.preventDefault();
            });

            // This variable is purely to indicate which values are allowed (true / false).
            var websiteHasAuthenticatedSession = false;
            // Inform the session extension about the current session state of the website. Keep in mind
            // this operation can only be performed once on every page load.
            session.configure({ active: websiteHasAuthenticatedSession });
          });
        }
      });
    </script>
  </body>
</html>

  • No labels