编程

Laravel 表单中添加 Google reCAPTCHA

818 2024-03-27 17:55:00

表单提交是许多网站的重要组成部分,但它们也可能成为垃圾信息和滥用的目标。

Captcha 是一个用来区分人类和机器人的挑战。其范围从在失真的图像中输入一系列字母到选择包含特定项目的图像。

谷歌使用这些相同的想法创建了 recaptcha,以保护网站免受欺诈、垃圾邮件和滥用。

图片验证: Google

Google reCAPTCHA 是谷歌提供的一项免费服务,有助于验证表单提交是由真人而非机器人提交的。为了确保 Laravel 表单受到保护,可以将谷歌 reCAPTTHA 添加到您的网站。

在本指南中,我将展示如何在 Laravel 中将 Google Recaptcha 添加到表单中,以保护网站。我将把 recaptcha 添加到登录和注册表单中。

如何在 Laravel 项目中启用 Recaptcha

1. 新建 Laravel 项目

你可以新建应用或跳过此步

laravel new recaptcha

我还将安装 Laravel breeze 以搭建一个简单的身份验证系统。

composer require laravel/breeze --dev
php artisan breeze:install

php artisan migrate
npm install
npm run dev

2. 添加 Recaptcha 脚本

Google 提供了一个可以添加到 head 的 recaptcha 脚本

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

将其添加到 breeze 生成的 Guest 布局文件中。

// resources/views/layouts/guest.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">

        <title>{{ config('app.name', 'Laravel') }}</title>

        <!-- Fonts -->
        <link rel="stylesheet" href="https://fonts.bunny.net/css2?family=Nunito:wght@400;600;700&display=swap">

        <!-- Scripts -->
        <script async src="https://www.google.com/recaptcha/api.js">// Add recaptcha script
        @vite(['resources/css/app.css', 'resources/js/app.js'])
    </head>
    <body class="font-sans text-gray-900 antialiased">
        <div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
            <div>
                <a href="/">
                    <x-application-logo class="w-20 h-20 fill-current text-gray-500" />
                </a>
            </div>

            <div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg">
                {{ $slot }}
            </div>
        </div>
    </body>
</html>

创建 ReCaptcha 管理员账号并添加网站

我们可以创建一个 Admin 账号并添加网站

添加网站

然后可以获得 site keysite secret,然后可以用于 Laravel 应用中。

Site Key 和 Site Secret

4. 更新 .env 文件及配置文件ons

有了 site key 和 site secret 后,我们可以将其添加到环境变量。首先新建一个配置文件 config/services.php。该文件在你想添加第三方配置时使用。

始终在配置文件中添加环境配置,不要直接在 Laravel 控制器中调用 env()。这是因为 Laravel 缓存配置,因此在运行时使用 bootstrap/config.php 中的单个配置文件来加载配置值。通过运行 artisan config:cache 命令,可以缓存和使用所有配置。

//config/services.php

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Third Party Services
    |--------------------------------------------------------------------------
    |
    | This file is for storing the credentials for third party services such
    | as Mailgun, Postmark, AWS and more. This file provides the de facto
    | location for this type of information, allowing packages to have
    | a conventional file to locate the various service credentials.
    |
    */

    'mailgun' => [
        'domain' => env('MAILGUN_DOMAIN'),
        'secret' => env('MAILGUN_SECRET'),
        'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
        'scheme' => 'https',
    ],

    'postmark' => [
        'token' => env('POSTMARK_TOKEN'),
    ],

    'ses' => [
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
    ],
    //Add these Configurations
    'recaptcha' => [
        'key' => env('RECAPTCHA_SITE_KEY'),
        'secret' => env('RECAPTCHA_SITE_SECRET'),
    ]
];

然后可以通过 config('services.recaptcha') 键引用配置。

5. 将 Recaptcha 添加到 Laravel 应用

谷歌提供了两个版本的 recaptcha。V2 是基于挑战的 recaptcha,而 v3 是基于分数的 recaptcha。你可以从两者中选择任何一个。在本教程中,我将选择 v2 版本,因为它是大多数人熟悉或交互过的版本。

要使用它,我们需要添加一个 div,其中包含 g-repatcha 的 CSS 类和站点密钥。我们可以将这个 div 放在任何表单中。我会把它添加到登录/注册表格中。

// resources/views/auth/login.blade.php

<x-guest-layout>
    <!-- Session Status -->
    <x-auth-session-status class="mb-4" :status="session('status')" />

    <form method="POST" action="{{ route('login') }}">
        @csrf

        <!-- Email Address -->
        <div>
            <x-input-label for="email" :value="__('Email')" />
            <x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus />
            <x-input-error :messages="$errors->get('email')" class="mt-2" />
        </div>

        <!-- Password -->
        <div class="mt-4">
            <x-input-label for="password" :value="__('Password')" />

            <x-text-input id="password" class="block mt-1 w-full"
                            type="password"
                            name="password"
                            required autocomplete="current-password" />

            <x-input-error :messages="$errors->get('password')" class="mt-2" />
        </div>

         <!-- Google Recaptcha -->
        <div class="g-recaptcha mt-4" data-sitekey={{config('services.recaptcha.key')}}></div>

        <!-- Remember Me -->
        <div class="block mt-4">
            <label for="remember_me" class="inline-flex items-center">
                <input id="remember_me" type="checkbox" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500" name="remember">
                <span class="ml-2 text-sm text-gray-600">{{ __('Remember me') }}</span>
            </label>
        </div>

        <div class="flex items-center justify-end mt-4">
            @if (Route::has('password.request'))
                <a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}">
                    {{ __('Forgot your password?') }}
                </a>
            @endif

            <x-primary-button class="ml-3">
                {{ __('Log in') }}
            </x-primary-button>
        </div>
    </form>
</x-guest-layout>

这会添加复选框到登录表单。

6. 在服务器级别验证响应。

无论选择 v2 还是 v3,它们都解析为单个 g-repatcha-response POST参数,我们可以使用该参数来验证用户响应是否成功。

在这一部分中,我们需要我们的服务器向谷歌发送 HTTP post 请求,并询问用户响应是否有效。

我们将向该端点发出请求: https://www.google.com/recaptcha/api/siteverify

我们将把逻辑添加到 laravel-breeze 生成的 AuthenticatedSession 控制器中。

//app/Http/Controllers/Auth/AuthenticatedSessionController.php

<?php

use Illuminate\Support\Facades\Http;
use Symfony\Component\HttpFoundation\IpUtils;

/**
     * Handle an incoming authentication request.
     */
    public function store(LoginRequest $request): RedirectResponse
    {
        $recaptcha_response = $request->input('g-recaptcha-response');

        if (is_null($recaptcha_response)) {
            return redirect()->back()->with('status', 'Please Complete the Recaptcha to proceed');
        }

        $url = "https://www.google.com/recaptcha/api/siteverify";

        $body = [
            'secret' => config('services.recaptcha.secret'),
            'response' => $recaptcha_response,
            'remoteip' => IpUtils::anonymize($request->ip()) //anonymize the ip to be GDPR compliant. Otherwise just pass the default ip address
        ];

        $response = Http::asForm()->post($url, $body);

        $result = json_decode($response);

        if ($response->successful() && $result->success == true) {
            $request->authenticate();

            $request->session()->regenerate();

            return redirect()->intended(RouteServiceProvider::HOME);
        } else {
            return redirect()->back()->with('status', 'Please Complete the Recaptcha Again to proceed');
        }
    }

在上面的代码中,我们在正文中附加了 site secret用户的 IP 地址和 Recaptcha 响应,谷歌将返回用户是否通过了 Recaptcha 的响应。

{
  "success": true|false,
  "challenge_ts": timestamp,  // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
  "hostname": string,         // the hostname of the site where the reCAPTCHA was solved
  "error-codes": [...]        // optional
}

如果用户没有通过响应,我们可以“安全地”假设他们“可能”是一个机器人,因此,我们可能会将他们重定向回他们可以尝试重新进行 captcha 挑战的形式。

另一方面,如果他们通过了 Recaptcha,我们可以处理表单输入,并可能将其存储在数据库中或执行进一步的验证。

FAQ

如何在本地测试 Recaptcha v3?

要在本地测试 Recaptcha,您需要将 localhost 域名添加到支持的域名列表中。你可以添加 127.0.0.1/ 作为 localhost 域名。

如何使用 ReCaptcha 运行自动测试?

要使用 ReCaptcha运行自动测试,你可以创建一个新的独立 site key 来测试 Repatcha v3。如果使用的是 Recaptcha v2,则可以使用以下测试密钥:
Site key: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
Secret key: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe

reCAPTCHA v2 和 v3 的不同?

Recaptcha v2 是一种基于挑战的验证,用户必须与 Recaptcha 插件交互才能验证其身份。

另一方面,Recaptcha v3 是一个基于分数的验证系统,不需要用户进行交互。与 v2 相比,它还提供了更多关于流量的数据点。

你可以根据需要选择其中任何一个。

reCAPTCHA v3 是否比 v2 更好?

Recaptcha v3 被认为比 v2 更好,因为它侵入性更小,并且在后台执行检查,从而消除用户所需的交互。

Recaptcha v3 还使用机器学习不断提高其区分人类和机器人流量的能力。此外,v3 是一个基于分数的系统,你可以自由设置何时阻止或允许表单提交的阈值。

在 Laravel 中能否在多个表单中使用 reCAPTCHA?

是的,您可以对同一网站/应用上的多个表单使用相同的 site key。

结论

总之,将 Google reCAPTCHA 添加到 Laravel 表单中是保护网站免受垃圾信息和滥用的有效方法。有了本指南,现在就有了将 reCAPTCHA 集成到表单中的知识和工具,并确保表单提交是由真人完成的。无论初学者还是经验丰富的开发人员,本教程都会为你提供入门所需的分步说明。

通过将 reCAPTCHA 添加到表单中,你可以确保网站的安全,并专注于重要的事情,如建立业务和与用户建立联系。

感谢阅读!