Symfony 7.1 和 AltCha - 响应状态代码 403

问题描述 投票:0回答:1

我有一个 Symfony 7.1 应用程序,我想通过 API 在我的联系表单中集成 AltCha

我总是收到 AltCha API 返回的状态代码 403:

{"error":"Invalid API Key.","statusCode":403}

首先,我认为钥匙是错误的。在我检查了这一点(并且密钥是正确的)后,我创建了一个新的,只是为了确定。

但仍然是同样的问题。我检查了 AltCha 文档,里面写着

403 Forbidden:API Key 可能与 Referer 标头不匹配。确保您发送具有适当来源的有效 Referer 标头,并且 API 密钥是为同一域创建的。

我在标题中有引用者。我只是找不到问题,我真的很感激任何帮助。

API 和 SecretKey 存储在 .env 文件中并被正确读取。

也许问题是,我正在尝试使用 localhost 在我的开发环境中执行此操作?

这是我的 KontaktController

<?php

namespace App\Controller;

use App\Entity\Kontakt;
use App\Form\KontaktType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\HttpClientInterface;

class KontaktController extends AbstractController
{
    private EntityManagerInterface $em;
    private HttpClientInterface $httpClient;
    private string $altchaSecretKey;
    private string $altchaApiKey;
    private LoggerInterface $logger;

    public function __construct(
        EntityManagerInterface $em,
        HttpClientInterface    $httpClient,
        string                 $altchaSecretKey,
        string                 $altchaApiKey,
        LoggerInterface        $logger
    )
    {
        $this->em = $em;
        $this->httpClient = $httpClient;
        $this->altchaSecretKey = $altchaSecretKey;
        $this->altchaApiKey = $altchaApiKey;
        $this->logger = $logger;
    }

    #[Route('/kontakt', name: 'app_kontakt')]
    public function index(Request $request, MailerInterface $mailer): Response
    {
        $title = 'Markus Michalski - Kontakt';
        $contact = new Kontakt();
        $form = $this->createForm(KontaktType::class, $contact);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $altchaToken = $form->get('altchaToken')->getData();

            // AltCha Verifizierung
            try {
                $altchaResponse = $this->httpClient->request('POST', 'https://eu.altcha.org/api/v1/challenge/verify', [
                    'headers' => [
                        'Content-Type' => 'application/json',
                        'Authorization' => 'Bearer ' . $this->altchaSecretKey,
                        'Referer' => $request->getSchemeAndHttpHost(),
                    ],
                    'json' => [
                        'payload' => $altchaToken,
                    ],
                ]);

                $statusCode = $altchaResponse->getStatusCode();
                $content = $altchaResponse->getContent(false);

                if ($statusCode !== 200) {
                    $this->logger->error("AltCha API returned status code $statusCode: $content");
                    throw new \Exception("AltCha verification failed");
                }

                $altchaResult = $altchaResponse->toArray();

                if (!$altchaResult['verified']) {
                    $this->addFlash('error', 'AltCha-Verifizierung fehlgeschlagen. Bitte versuchen Sie es erneut.');
                    return $this->renderFormWithData($form, $title);
                }
            } catch (\Exception $e) {
                $this->logger->error('AltCha verification failed: ' . $e->getMessage());
                $this->addFlash('error', 'Ein Fehler ist bei der Verifizierung aufgetreten. Bitte versuchen Sie es später erneut.');
                return $this->renderFormWithData($form, $title);
            }

            // Form data processing

            $contact = $form->getData();
            $contact->setTimestamp(new \DateTime('now'));
            $this->em->persist($contact);
            $this->em->flush();

            $email = new TemplatedEmail();
            $email
                ->from(new Address('XXXX', 'Kontaktformular'))
                ->to('XXXXX')
                ->subject('Anfrage über das Kontaktformular')
                ->htmlTemplate('email/kontaktSelf.html.twig')
                ->locale('de')
                ->context(['contact' => $contact, 'title' => $title]);
            try {
                $mailer->send($email);
            } catch (TransportExceptionInterface $exception) {
                $rep = $this->em->getRepository(Kontakt::class);
                $updateContact = $rep->findOneBy(['id' => $contact->getId()]);
                $updateContact->setExeption($exception->getMessage());
                $this->em->persist($updateContact);
                $this->em->flush();
            }

            return $this->render('kontakt/success.html.twig', [
                'title' => $title,
                'contact' => $contact,
            ]);
        }

        return $this->renderFormWithData($form, $title);
    }

    private function renderFormWithData($form, $title): Response
    {
        return $this->render('kontakt/index.html.twig', [
            'title' => $title,
            'form' => $form->createView(),
            'altchaApiKey' => $this->altchaApiKey,
        ]);
    }
}

我的树枝模板看起来像这样:

{% extends 'base.html.twig' %}

{% block body %}
    <main>
        
        <section class="section">
            <h1>Kontaktformular</h1>
            {% for label, messages in app.flashes %}
                {% for message in messages %}
                    <div class="alert alert-{{ label == 'error' ? 'danger' : label }}">
                        {{ message }}
                    </div>
                {% endfor %}
            {% endfor %}
            {{ form_start(form) }}
            {{ form_errors(form) }}

            <label for="name">{{ field_label(form.name) }}</label>
            <input type="text" id="name" name="{{ field_name(form.name) }}" required value="{{ field_value(form.name) }}">
            {% if form.name.vars.errors|length > 0 %}
                <div class="contact_error">
                    {{ form_errors(form.name) }}
                </div>
            {% endif %}
            <label for="email">{{ field_label(form.email) }}</label>
            <input type="email" id="email" name="{{ field_name(form.email) }}" required value="{{ field_value(form.email) }}">
            {% if form.email.vars.errors|length > 0 %}
                <div class="contact_error">
                    {{ form_errors(form.email) }}
                </div>
            {% endif %}
            <label for="subject">{{ field_label(form.subject) }}</label>
            <input type="text" id="subject" name="{{ field_name(form.subject) }}" required value="{{ field_value(form.subject) }}">
            {% if form.subject.vars.errors|length > 0 %}
                <div class="contact_error">
                    {{ form_errors(form.subject) }}
                </div>
            {% endif %}
            <label for="message">{{ field_label(form.message) }}</label>
            <textarea id="message" name="{{ field_name(form.message) }}" rows="5" required>{{ field_value(form.message) }}</textarea>
            {% if form.message.vars.errors|length > 0 %}
                <div class="contact_error">
                    {{ form_errors(form.message) }}
                </div>
            {% endif %}
            <div class="agree-terms checkbox-container">
                {{ form_widget(form.agreeTerms, {'attr': {'class': 'checkbox-input'}}) }}
                <span class="checkbox-label">Ich habe die <a href="{{ path('app_datenschutz') }}" target="_blank">Datenschutzbestimmungen</a> zur Kenntnis genommen. </span>
            </div>

            {# AltCha Widget hinzufügen #}
            <altcha-widget
                    challengeurl="https://eu.altcha.org/api/v1/challenge?apiKey={{ altchaApiKey }}"
                    spamfilter
            ></altcha-widget>

            {{ form_widget(form.send) }}
            {{ form_rest(form) }}
            {{ form_end(form) }}
            <div class="contact-required-text">Alle Felder sind Pflichtfelder!</div>
        </section>

    </main>
{% endblock %}

{% block javascripts %}
    {{ parent() }}
    <script async defer type="module" src="https://eu.altcha.org/js/latest/altcha.min.js"></script>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const form = document.querySelector('form[name="kontakt"]');
            const altchaWidget = document.querySelector('altcha-widget');

            form.addEventListener('submit', function(event) {
                event.preventDefault();

                altchaWidget.verify().then(function(token) {
                    document.getElementById('kontakt_altchaToken').value = token;
                    form.submit();
                }).catch(function(error) {
                    console.error('AltCha verification failed:', error);
                    // TODO ErrorMessage
                });
            });
        });
    </script>
{% endblock %}
php captcha symfony7
1个回答
0
投票

API 密钥必须注册完整的

host
,包括端口(如果使用非标准端口)。如果您使用
localhost:8080
,请在 API 密钥注册期间输入整个主机。

© www.soinside.com 2019 - 2024. All rights reserved.