Hier eine Implementierung von Google reCAPTCHA in einer Extbase Extension. Als Beispiel dient ein simples Anmeldeformular (E-Mail, Captcha). Die reCAPTCHA Response wird hierbei nicht im Model als Property gehalten sonder als separates Controller-Argument übergeben und ist via Annotations mit dem Validator verknüpft. Somit kann die Überprüfung des Captcha unabhängig von der eigentlichen Domain Object Validierung erfolgen. Sowohl "Website Key" als auch "Secret Key" sind dynamisch via Typoscript definiert.

Beim (bzw. kurz vor) Absenden des Formulars wird die reCAPTCHA Response von Google angefordert und diese die entsprechende (hidden) Property des Formulares geschrieben. Bei der serverseitigen Verarbeitung des Scripts wird die über das Formular übermittelte Response innerhalb des Validators gegen die reCAPTCHA API validiert.

ReCaptcha Validator

<?php

namespace Vendor\Extension\Validation\Validator;

/**
 * ReCaptchaValidator
 */
class ReCaptchaValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator 
{

    /**
     *
     * @var bool
     */
    protected $acceptsEmptyValues = false;
    
    /**
     * Object Manager
     *
     * @var \TYPO3\CMS\Extbase\Object\ObjectManager
     * @TYPO3\CMS\Extbase\Annotation\Inject
     */
    protected $objectManager;

    /**
     * Checks the google recaptcha response
     *
     * @param mixed $reCaptchaResponse The captcha response that should be validated
     * @api
     */
    public function isValid($reCaptchaResponse) 
    {
        
        /** @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManager $configurationManager */
        $configurationManager = $this->objectManager->get(\TYPO3\CMS\Extbase\Configuration\ConfigurationManager::class);
        $settings = $configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS);
                
        $json = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' . $settings['global']['googleReCaptchaSecretKey'] . '&response=' . $reCaptchaResponse);
        $data = json_decode($json);
        if (!$data || !$data->success || $data->success != true) {
            $this->addError('ReCaptcha', 1905031100);
        }
    }

}

Extbase Controller

<?php

namespace Vendor\Extension\Controller;

/**
 * ContactController
 */
class ContactController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {

    /**
     * action create
     *
     * @param \Vendor\Extension\Domain\Model\Contact $newContact
     * @param string $reCaptchaResponse
     * @TYPO3\CMS\Extbase\Annotation\Validate("Vendor\Extension\Validation\Validator\ReCaptchaValidator", param="reCaptchaResponse")
     * @return void
     */
    public function createAction(\Vendor\Extension\Domain\Model\Contact $newContact, $reCaptchaResponse) {

    }   

}

FLUID Template

<f:form action="create" id="contact-form" name="newContact" object="{newContact}">

	<div class="form-group">
		<label for="email">E-Mail *</label>
		<f:form.textfield id="email" class="form-control" property="email" />
	</div>
	
	<div class="form-group">
		<label>Spamschutz *</label>
		<div class="<f:form.validationResults for="reCaptchaResponse"><f:if condition="{validationResults.flattenedErrors}">alert alert-danger</f:if></f:form.validationResults>">
			<div class="g-recaptcha" data-sitekey="{settings.global.googleReCaptchaWebsiteKey}"></div>
		</div>
		<f:form.hidden name="reCaptchaResponse" id="reCaptchaResponse" class="form-control" />
	</div>
	
	<div class="form-group">
		<button type="submit" class="btn btn-default submit recaptcha">Absenden</button>
	</div>
	
	<script src="https://www.google.com/recaptcha/api.js?hl={twoLetterIsoCode}" async defer></script>
	
</f:form>

Javascript

$(document).ready(function () {

    $('.submit.recaptcha').click(function () {
        $('#recaptchaResponse').val(grecaptcha.getResponse());
    });

});