M

Suivez nous

Intégrer reCAPTCHA à un formulaire personnalisé sous Magento 2

Depuis plusieurs années, les Captcha sont devenus monnaie courante sur les formulaires présents sur les sites web. Le système a considérablement évolué au fil du temps, jusqu’à la version 3 actuelle. Alors qu’il fallait auparavant résoudre un test visuel, reCAPTCHA V3 fonctionne désormais de manière invisible en analysant le comportement de l’utilisateur pour attribuer un score, déterminant la probabilité qu’il s’agisse d’un humain ou d’un robot.

Configuration de reCAPTCHA dans Magento 2

Magento 2 propose nativement l’intégration de Google reCAPTCHA, notamment sur les formulaires de création de compte ou de contact. Il est possible d’activer ou non cet outil directement depuis le back-office, ainsi que de choisir la version utilisée.

Pour configurer reCAPTCHA V3, il faut se rendre dans :
Stores -> Configuration -> Security -> Google reCAPTCHA Storefront.

Les étapes de configuration sont les suivantes :

  • Renseigner la clé publique et la clé privée, disponibles sur : Google reCAPTCHA Console.
    Bien que Google tende à supprimer progressivement la nécessité de la clé privée selon les cas d’usage, Magento 2 en a encore besoin actuellement.
    Pour retrouver cette clé, il suffit de sélectionner la clé d’API souhaitée puis de se rendre dans intégration. Dans ce cas 2 possibilités, soit il y a un bouton « Intégrer à un service tiers ou un plug-in », soit un bouton « Utiliser l’ancienne clé ».
  • Définir le score minimal de confiance, compris entre 0 et 1 (0 représentant très probablement un robot, 1 un humain). Un score supérieur à 0.5 est généralement recommandé.

Une fois cette configuration effectuée, il est possible de choisir les formulaires sur lesquels reCAPTCHA sera actif via la section Storefront.

Évolution vers un reCAPTCHA sans clé privée

Bien que, pour l’heure, la clé privée de Google reCAPTCHA reste accessible et nécessaire dans Magento 2, Google tend progressivement vers un modèle, notamment avec reCAPTCHA V3, où seule la clé publique est requise.

Cette évolution simplifie l’intégration côté serveur, mais oblige également les plateformes comme Magento à adapter leur code pour s’aligner sur cette nouvelle logique.

Tant que Magento 2 n’a pas supprimé cette dépendance, il faudra continuer à renseigner la clé privée. Toutefois, lors de prochaines mises à jour de Magento, la gestion de reCAPTCHA pourrait évoluer, voire changer complètement.

Mais qu’en est-il lorsqu’on souhaite utiliser un captcha sur un formulaire personnalisé ?

Intégration de reCAPTCHA sur un formulaire personnalisé

1. Ajout de l’option dans le back-office

Commencez par ajouter une entrée dans l’interface d’administration pour activer le captcha sur votre formulaire personnalisé. Cela se fait dans le fichier etc/adminhtml/system.xml :

<section id="recaptcha_frontend">
    <group id="type_for">
        <field id="custom_form" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1">
            <label>Enable for Custom Form</label>
            <source_model>Magento\ReCaptchaAdminUi\Model\OptionSource\Type</source_model>
        </field>
    </group>
</section>

2. Ajout du bloc reCAPTCHA au formulaire

Ensuite, dans le fichier de layout, dans le bloc de votre formulaire, ajoutez un bloc reCAPTCHA :

<block name="custom.form" template="My_Module::custom_form.phtml">
    <block class="Magento\ReCaptchaUi\Block\ReCaptcha"
        name="recaptcha"
        template="Magento_ReCaptchaFrontendUi::recaptcha.phtml"
        ifconfig="recaptcha_frontend/type_for/custom_form"> <!-- chemin vers la configuration du captcha -->
        <arguments>
            <argument name="recaptcha_for" xsi:type="string">custom_form</argument> <!-- nom du champs de configuration du captcha -->
            <argument name="jsLayout" xsi:type="array">
                <item name="components" xsi:type="array">
                    <item name="recaptcha" xsi:type="array">
                        <item name="component" xsi:type="string">Magento_ReCaptchaFrontendUi/js/reCaptcha</item>
                    </item>
                </item>
            </argument>
        </arguments>
    </block>
</block>

Dans le fichier template correspondant, vous pouvez alors intégrer le bloc comme ceci :

<form action="<?= $block->getUrl('form/send') ?>" method="post" id="custom-form">
    <div>
        <input name="fullname" id="fullname" title="fullname" value="" type="text">
    </div>
    <div>
        <input name="telephone" id="telephone" title="telephone" value="" type="tel">
    </div>
    <div>
        <input name="email" id="email" title="email" value="" type="email">
    </div>
    <?= $block->getChildHtml('recaptcha'); ?> <!-- appel du block -->
    <button class="action secondary" data-role="custom-form-submit">
        <span><?= __('Send form'); ?></span>
    </button>
</form>

À ce stade, le reCAPTCHA s’affichera sur le formulaire, mais la logique de validation côté serveur reste à mettre en place.

3. Vérification côté serveur

Créez un observer qui interviendra avant toute action sur votre formulaire :

<?php

namespace My\Module\Observer;

use Magento\Framework\App\Response\HttpFactory;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\UrlInterface;
use Magento\ReCaptchaUi\Model\IsCaptchaEnabledInterface;
use Magento\ReCaptchaUi\Model\RequestHandler;

class CustomFormObserver implements ObserverInterface
{
    public function __construct(
        private IsCaptchaEnabledInterface $isCaptchaEnabled,
        private UrlInterface $url,
        private RequestHandler $requestHandler,
        private HttpFactory $responseFactory,
    ) {
    }

    public function execute(Observer $observer): void
    {
        $key = 'custom_form'; //Le nom donné au captcha
        if (!$this->isCaptchaEnabled->isCaptchaEnabledFor($key)) {
            return; //Si le captcha n'est pas activé, il n'est pas nécessaire de continuer
        }

        $request = $observer->getRequest(); //On récupère la request de la class sur laquelle on applique l'observer
        $response = $this->responseFactory->create();
        $redirectOnFailureUrl = $request->getServer('HTTP_REFERER') ?? $this->url->getUrl('*/*/index'); //Redirection en cas d'échec du captcha

        $this->requestHandler->execute($key, $request, $response, $redirectOnFailureUrl); //On execute la vérification
    }
}

Déclarez ensuite cet observer dans etc/frontend/events.xml :

<event name="controller_action_predispatch_form_send">
    <observer name="recaptcha_on_custom_form" instance="My\Module\Observer\CustomFormObserver"/>
</event>

Aucune logique supplémentaire n’est requise si le formulaire est soumis classiquement.

4. Cas particulier : soumission via AJAX

Si votre formulaire est soumis via un événement JavaScript (par exemple un click), sans utiliser la méthode submit, le reCAPTCHA risque de ne pas fonctionner correctement. En effet, si l’on regarde dans le DOM, un champs textarea caché est présent. Celui-ci va accueillir une clé qui est générée à la soumission et donc ne sera pas initialisé dans ce cas.

Voici un exemple de code pour contourner ce problème :

handleCustomFormSubmit: function () {
    let _self = this;

    $('#custom-form').on('submit', function (e) {
        e.preventDefault();
        return false;
    });

    $('button[data-role="custom-form-submit"]').on('click', function () {
        var form = $('#custom-form');

        if (form.validation() && form.validation('isValid')) {
            form.trigger('submit');

            let captchaField = form.find('[name*="g-recaptcha-response"]');

            if (captchaField.length) {
                const originalFetch = window.fetch;
                window.fetch = async function (...args) {
                    const [url] = args;

                    if (typeof url === 'string' && url.includes('https://www.google.com/recaptcha/api2')) {
                        _self.customFormSubmit();
                        captchaField.val('');
                        window.fetch = originalFetch;
                    }

                    return originalFetch.apply(this, args);
                };
            } else {
                _self.customFormSubmit();
            }
        }

        return false;
    });
}

Ce code :

  • Simule une soumission classique pour forcer la génération du token reCAPTCHA.
  • Récupère le champ g-recaptcha-response contenant la clé. Il est nécessaire de vérifier si cette clé existe dans le cas où reCAPTCHA est désactivé sur ce formulaire.
  • Surveille les requêtes AJAX pour détecter celle de reCAPTCHA, et lance ensuite la soumission personnalisée.

Avec ces étapes, vous pouvez intégrer efficacement Google reCAPTCHA sur vos formulaires personnalisés dans Magento 2, tout en garantissant leur bon fonctionnement, même en cas de soumission asynchrone.