karser/karser-recaptcha3-bundle

Google ReCAPTCHA v3 for Symfony

安装次数: 1,361,553

依赖项: 6

建议者: 2

安全: 0

星标: 160

关注者: 8

分支: 21

开放问题: 5

类型:symfony-bundle


README

Build Status Scrutinizer Code Quality Code Coverage Total Downloads

reCAPTCHA v3 在不影响用户体验的情况下为每个请求返回一个分数。该分数基于与您的网站的交互(1.0 表示非常可能是一次良好的交互,0.0 表示非常可能是机器人)并允许您为您的网站采取适当的措施。在此处注册 reCAPTCHA v3 密钥 这里

image

安装

使用 composer,需要

composer require karser/karser-recaptcha3-bundle

您可以通过使用 symfony/flex 快速配置此扩展包

  • 对于 google/recaptcha 回答
  • 对于 karser/karser-recaptcha3-bundle 回答 image

不使用 symfony/flex 的配置

1. 注册扩展包

Symfony 4/5/6/7 版本
将扩展包注册到 config/bundles.php

return [
    //...
    Karser\Recaptcha3Bundle\KarserRecaptcha3Bundle::class => ['all' => true],
];

Symfony 3 版本
将扩展包注册到 app/AppKernel.php

public function registerBundles()
{
    return array(
        // ...
        new Karser\Recaptcha3Bundle\KarserRecaptcha3Bundle(),
    );
}

2. 添加配置文件

# config/packages/karser_recaptcha3.yaml (or app/config/config.yml if using Symfony3)

karser_recaptcha3:
    site_key: '%env(RECAPTCHA3_KEY)%'
    secret_key: '%env(RECAPTCHA3_SECRET)%'
    score_threshold: 0.5

将您的网站密钥和密钥添加到您的 .env 文件中

###> karser/recaptcha3-bundle ###
RECAPTCHA3_KEY=my_site_key
RECAPTCHA3_SECRET=my_secret
###< karser/recaptcha3-bundle ###

使用

如何在 Symfony 表单中集成 re-captcha

<?php

use Karser\Recaptcha3Bundle\Form\Recaptcha3Type;
use Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3;

class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('captcha', Recaptcha3Type::class, [
            'constraints' => new Recaptcha3(),
            'action_name' => 'homepage',
            'script_nonce_csp' => $nonceCSP,
            'locale' => 'de',
        ]);
    }
}

注意

  • action_name 参数是 reCAPTCHA v3 操作,它用于在 Google reCAPTCHA 控制台中识别此特定表单的提交,并在后端进行确认是推荐的额外安全步骤。
  • script_nonce_csp 参数是可选的。您必须使用与您的 Content-Security Policy 标头中相同的 nonce。
  • locale 参数是可选的。它默认为英语,并控制 reCaptcha 小部件的语言。

如何在全球范围内(即使在中国)使用 reCAPTCHA

当 'www.google.com' 不可访问时,在您的代码中使用 'www.recaptcha.net' 主机。

# config/packages/karser_recaptcha3.yaml (or app/config/config.yml if using Symfony3)

karser_recaptcha3:
    host: 'www.recaptcha.net' # default is 'www.google.com'

如何为不同的区域设置 captcha 语言?

您可以通过设置上面的选项中的区域来控制小部件显示的语言。

要更改错误消息,您应安装 Symfony 翻译组件

然后,将验证文本替换为消息和 messageMissingValue 选项的消息键。

$builder->add('captcha', Recaptcha3Type::class, [
     'constraints' => new Recaptcha3 ([
         'message' => 'karser_recaptcha3.message',
         'messageMissingValue' => 'karser_recaptcha3.message_missing_value',
     ]),
]);

添加英语、西班牙语或任何其他翻译

# translations/validators/validators.en.yaml
karser_recaptcha3.message: 'Your computer or network may be sending automated queries'
karser_recaptcha3.message_missing_value: 'The captcha value is missing'

# translations/validators/validators.es.yaml
karser_recaptcha3.message: 'Es posible que su computadora o red esté enviando consultas automatizadas'
karser_recaptcha3.message_missing_value: 'Falta el valor de captcha'

如何获取 ReCaptcha 分数

在表单提交后注入 Recaptcha3Validator 并调用 getLastResponse()->getScore()

<?php

use Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3Validator;

class TaskController extends AbstractController
{
    public function new(Request $request, Recaptcha3Validator $recaptcha3Validator): Response
    {
        //...
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            //...
            $score = $recaptcha3Validator->getLastResponse()->getScore();
            //...
        }
        //...
    }
}

如何将 re-captcha 集成到 API 方法中

思想是要求前端提交 captcha 令牌,因此它将在服务器端进行验证。

首先,您需要将 captcha 字段添加到您的传输实体中

<?php

namespace App\Dto;

final class UserSignupRequest
{
    /** @var string|null */
    public $email;

    /** @var string|null */
    public $captcha;
}

然后添加验证约束

#config/validator/validation.yaml
App\Dto\UserSignupRequest:
    properties:
        email:
            - NotBlank: ~
            - Email: { mode: strict }
        captcha:
            - Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3: ~

在前端部分,您需要提交 captcha 令牌以及电子邮件。您可以在页面加载时或表单提交时获取 captcha 令牌。

<script src="https://www.google.com/recaptcha/api.js?render=<siteKey>"></script>

<script>
const siteKey = '*****************-**-******-******';

//either on page load
grecaptcha.ready(function() {
    grecaptcha.execute(siteKey, {
        action: 'homepage'
    }).then(function(token) {
        //the token will be sent on form submit
        $('[name="captcha"]').val(token);
        //keep in mind that token expires in 120 seconds so it's better to add setTimeout.
    });
});

//or on form post:
grecaptcha.ready(function() {
    grecaptcha.execute(siteKey, {
        action: 'homepage'
    }).then(function(token) {
        //submit the form
        return http.post(url, {email, captcha: token});
    });
});
</script>

如何显示 captcha 响应的错误

只需将 {{ errorCodes }} 变量添加到消息模板中即可

$formBuilder->add('captcha', Recaptcha3Type::class, [
    'constraints' => new Recaptcha3(['message' => 'There were problems with your captcha. Please try again or contact with support and provide following code(s): {{ errorCodes }}']),
])

如何处理功能性和端到端测试

Recaptcha不允许你高效地测试你的应用程序,除非你禁用测试环境的Recaptcha。

# app/config/config.yml (or config/packages/karser_recaptcha3.yaml if using Symfony4)
karser_recaptcha3:
    enabled: '%env(bool:RECAPTCHA3_ENABLED)%'
#.env.test or an environment variable
RECAPTCHA3_ENABLED=0

如何从PHP动态设置阈值,而不是从.yaml配置或.env文件中设置?

你应该在你的服务中注入@karser_recaptcha3.google.recaptcha,并调用setScoreThreshold方法。

#services.yaml
App\Services\YourService:
    arguments: ['@karser_recaptcha3.google.recaptcha']
#App/Services/YourService.php

use ReCaptcha\ReCaptcha;

class YourService {
    private $reCaptcha;

    public function __construct(ReCaptcha $reCaptcha) {
        $this->reCaptcha = $reCaptcha;
    }

    public function yourMethod() {
        $this->reCaptcha->setScoreThreshold(0.7);
    }
}

如何在Cloudflare后面正确解析IP地址?

根据Cloudflare文档:为了为每个请求到源站提供客户端(访问者)的IP地址,Cloudflare会添加CF-Connecting-IP头。

"CF-Connecting-IP: A.B.C.D"

因此,你可以实现一个自定义IP解析器,尝试读取CF-Connecting-IP头,或者在内部IP解析器回退。

<?php declare(strict_types=1);

namespace App\Service;

use Karser\Recaptcha3Bundle\Services\IpResolverInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class CloudflareIpResolver implements IpResolverInterface
{
    /** @var IpResolverInterface */
    private $decorated;

    /** @var RequestStack */
    private $requestStack;

    public function __construct(IpResolverInterface $decorated, RequestStack $requestStack)
    {
        $this->decorated = $decorated;
        $this->requestStack = $requestStack;
    }

    public function resolveIp(): ?string
    {
        return $this->doResolveIp() ?? $this->decorated->resolveIp();
    }

    private function doResolveIp(): ?string
    {
        $request = $this->requestStack->getCurrentRequest();
        if ($request === null) {
            return null;
        }
        return $request->server->get('HTTP_CF_CONNECTING_IP');
    }
}

以下是服务声明。它装饰了内部解析器。

#services.yaml
services:
    App\Service\CloudflareIpResolver:
        decorates: 'karser_recaptcha3.ip_resolver'
        arguments:
            $decorated: '@App\Service\CloudflareIpResolver.inner'
            $requestStack: '@request_stack'

Symfony HttpClient集成

如果你的应用程序依赖于symfony/http-client,那么它将通过RequestMethod/SymfonyHttpClient自动连接使用。

故障排除清单

请确保你设置了版本3的recaptcha密钥/密钥。

此外,请确保你已在recaptcha设置中添加了使用的域名。通常开发域与生产域不同,因此最好再次确认。image

确保你在渲染的表单的HTML中看到这一点。

<input type="hidden" id="form_captcha" name="form[captcha]" /><script>
    var recaptchaCallback_form_captcha = function() {
    grecaptcha.execute('<YOUR-RECAPTCHA-KEY>', {action: 'landing'}).then(function(token) {
    document.getElementById('form_captcha').value = token;
    });
    };
    </script><script src="https://www.google.com/recaptcha/api.js?render=<YOUR-RECAPTCHA-KEY>&onload=recaptchaCallback_form_captcha" async defer></script> 
</form>

确保浏览器控制台中没有JavaScript错误。

测试

composer update
vendor/bin/phpunit