承接 danieledesantis/laravel-cloudflare-turnstile-react-blade 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

danieledesantis/laravel-cloudflare-turnstile-react-blade

最新稳定版本:1.0.0

Composer 安装命令:

composer require danieledesantis/laravel-cloudflare-turnstile-react-blade

包简介

Cloudflare Turnstile integration for Laravel with support for React, Inertia.js and Blade

README 文档

README

Latest Version on Packagist Total Downloads

Cloudflare Turnstile integration for Laravel with built-in support for Blade, React, and Inertia.js. Protect your Laravel applications from bots and abuse with Cloudflare's free CAPTCHA alternative.

Quickstart

Read the Quick Start Guide to get up and running in 5 minutes.

Features

  • Easy Integration - Drop-in Blade components and React hooks
  • Multiple Frameworks - Support for Blade, React and Inertia.js
  • Secure - Server-side validation with customizable rules
  • Testable - Built-in testing mode for automated tests
  • Configurable - Extensive configuration options
  • Middleware Support - Protect routes with middleware
  • Validation Rules - Custom Laravel validation rules
  • IP Whitelisting - Skip verification for trusted IPs

Requirements

  • PHP 8.1 or higher
  • Laravel 10.x or higher
  • A Cloudflare Turnstile site key and secret key

Installation

Step 1: Install via Composer

composer require danieledesantis/laravel-cloudflare-turnstile-react-blade

Step 2: Publish Configuration

php artisan vendor:publish --tag=turnstile-config

Step 3: Publish Components

Publish React/TypeScript Components (for React/Inertia.js projects)

If you are using React or Inertia.js, publish the TypeScript components:

php artisan vendor:publish --tag=turnstile-components

This will publish the components to resources/js/Components/Turnstile/:

  • hooks/useTurnstile.tsx - React hook for Turnstile
  • components/Turnstile.tsx - React component for Turnstile
  • index.ts - Exports

You can then import them directly in your code:

import { useTurnstile, Turnstile } from '@/Components/Turnstile';

Publish Blade Components (for Blade projects)

If you are using the Blade templating engine, publish the component:

php artisan vendor:publish --tag=turnstile-views

This will publish the component to resources/views/vendor/turnstile/components/turnstile-widget.blade.php.

You can now use it in your code:

<x-turnstile />

Step 4: Configure Environment Variables

Add your Cloudflare Turnstile credentials to your .env file:

TURNSTILE_SITEKEY=your-site-key
TURNSTILE_SECRETKEY=your-secret-key

Get your keys from Cloudflare Dashboard.

  1. Go to Cloudflare Dashboard
  2. Navigate to Turnstile in the sidebar
  3. Click Add Site
  4. Enter your domain name
  5. Choose widget mode (recommended: Managed)
  6. Copy your Site Key and Secret Key

Usage

Step 1: Add Laravel Validation

You can add Laravel validation for the Cloudflare Turnstile response using one of the following methods:

Using the Validation Rule

use DanieleDeSantis\LaravelTurnstile\Http\Rules\TurnstileValidation;

public function store(Request $request)
{
    $request->validate([
        'email' => 'required|email',
        'password' => 'required',
        'cf-turnstile-response' => ['required', new TurnstileValidation()],
    ]);

    // Your logic here
}

Using the Facade

use DanieleDeSantis\LaravelTurnstile\Facades\Turnstile;

public function store(Request $request)
{
    try {
        Turnstile::verify(
            $request->input('cf-turnstile-response'),
            $request->ip()
        );

        // Verification successful
    } catch (\Exception $e) {
        return back()->withErrors(['turnstile' => $e->getMessage()]);
    }
}

Middleware

Protect entire routes or route groups:

use DanieleDeSantis\LaravelTurnstile\Http\Middleware\VerifyTurnstile;

// In routes/web.php
Route::post('/contact', [ContactController::class, 'store'])
    ->middleware('turnstile');

// With custom token field
Route::post('/register', [RegisterController::class, 'store'])
    ->middleware('turnstile:captcha-token');

Step 2: Add Cloudflare Turnstile widget to the frontend

React / Inertia.js

Publish the React components using

php artisan vendor:publish --tag=turnstile-components

Pass the sitekey to your component

return Inertia::render('Auth/Login', [
    'turnstile_sitekey' => config('turnstile.sitekey'),
]);

Add the widget to you form using one of the following methods:

Using the React Component
import { Turnstile } from '@/Components/Turnstile';
import { useForm } from '@inertiajs/react';

export default function LoginForm({ turnstile_sitekey }) {
    const { data, setData, post, processing, errors } = useForm({
        // Your form fields
        'cf-turnstile-response': '',
    });

    const submit = e => {
        e.preventDefault();
        post(route('login'));
    };

    return (
        <form>
            {/* Your form fields */}
            
            <Turnstile
                sitekey={turnstile_sitekey}
                onSuccess={(token: string) => setData('cf-turnstile-response', token)}
                onError={() => setData('cf-turnstile-response', '')}
                onExpire={() => setData('cf-turnstile-response', '')}
                theme='auto'
                size='normal'
            />

            <button type='submit'>Login</button>
        </form>
    );
}
Using the React Hook
import { useTurnstile } from '@/Components/Turnstile';
import { useForm } from '@inertiajs/react';

export default function LoginForm({ turnstile_sitekey }) {
    const { data, setData, post } = useForm({
        // Your form fields
        'cf-turnstile-response': '',
    });

    const { turnstileRef } = useTurnstile({
        sitekey: turnstile_sitekey,
        onSuccess: (token: string) => setData('cf-turnstile-response', token),
        onError: () => setData('cf-turnstile-response', ''),
        onExpire: () => setData('cf-turnstile-response', ''),
    });

    const submit = e => {
        e.preventDefault();
        post(route('login'));
    };

    return (
        <form onSubmit={submit}>
            {/* Your form fields */}

            <div ref={turnstileRef}></div>

            <button type='submit'>Login</button>
        </form>
    );
}
TypeScript Types

The package includes full TypeScript support:

interface Window {
    turnstile?: {
        render: (element: HTMLElement, options: TurnstileOptions) => string;
        reset: (widgetId: string) => void;
        remove: (widgetId: string) => void;
    };
}

Blade Components

Publish the Blade components using

php artisan vendor:publish --tag=turnstile-views

Add the component to your forms:

<form method="POST" action="/login">
    @csrf

    <!-- Your form fields -->

    <x-turnstile />

    <button type="submit">Login</button>
</form>
Customizing the Widget
<x-turnstile
    theme="dark"
    size="compact"
    field-name="captcha-token"
/>

Available options:

  • theme: auto, light, or dark (default: auto)
  • size: normal, compact, or flexible (default: normal)
  • field-name: Custom field name (default: cf-turnstile-response)
  • callback: JavaScript callback function name
  • error-callback: Error callback function name
  • expired-callback: Expired callback function name

Configuration

The configuration file config/turnstile.php provides extensive customization:

return [
    // Enable/disable Turnstile globally
    'enabled' => env('TURNSTILE_ENABLED', true),

    // Your Cloudflare credentials
    'sitekey' => env('TURNSTILE_SITEKEY', ''),
    'secretkey' => env('TURNSTILE_SECRETKEY', ''),

    // Verification endpoint
    'endpoint' => 'https://challenges.cloudflare.com/turnstile/v0/siteverify',

    // Request timeout in seconds
    'timeout' => 10,

    // Custom error messages
    'error_messages' => [
        'verification_failed' => 'The security verification failed. Please try again.',
        'missing_token' => 'Security verification is required.',
        'timeout' => 'Security verification timed out. Please try again.',
    ],

    // Testing mode (bypasses verification)
    'testing' => env('TURNSTILE_TESTING', env('APP_ENV') === 'testing'),

    // Skip verification for these IPs
    'skip_ips' => [],

    // Widget appearance
    'theme' => 'auto', // auto, light, dark
    'size' => 'normal', // normal, compact, flexible
];

Testing

The package automatically bypasses Turnstile verification when APP_ENV=testing or TURNSTILE_TESTING=true.

In Your Tests

use DanieleDeSantis\LaravelTurnstile\Facades\Turnstile;

class LoginTest extends TestCase
{
    public function test_user_can_login()
    {
        // Turnstile is automatically disabled in testing
        $response = $this->post('/login', [
            'email' => 'test@example.com',
            'password' => 'password',
            'cf-turnstile-response' => 'test-token', // Any value works
        ]);

        $response->assertRedirect('/dashboard');
    }

    public function test_turnstile_verification()
    {
        // Enable verification for specific tests
        Turnstile::disableTesting();

        // Your test logic

        // Re-enable testing mode
        Turnstile::enableTesting();
    }
}

Running Package Tests

composer install
./vendor/bin/phpunit

Advanced Usage

Programmatic Verification

use DanieleDeSantis\LaravelTurnstile\Facades\Turnstile;

// Check if Turnstile is enabled
if (Turnstile::isEnabled()) {
    // Get the site key
    $siteKey = Turnstile::getSiteKey();
}

// Verify a token
try {
    $verified = Turnstile::verify($token, $ipAddress);
} catch (TurnstileVerificationException $e) {
    // Handle verification failure
    $errorCodes = $e->getErrorCodes();
}

IP Whitelisting

Skip verification for trusted IPs (useful for local development):

TURNSTILE_SKIP_IPS=127.0.0.1,192.168.1.100

Or in config/turnstile.php:

'skip_ips' => ['127.0.0.1', '::1'],

Custom Error Messages

Customize error messages in config/turnstile.php:

'error_messages' => [
    'verification_failed' => 'Custom verification failed message',
    'missing_token' => 'Custom missing token message',
    'timeout' => 'Custom timeout message',
],

Controller Example (Complete)

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use Illuminate\Http\RedirectResponse;
use Inertia\Inertia;
use Inertia\Response;

class AuthenticatedSessionController extends Controller
{
    public function create(): Response
    {
        return Inertia::render('Auth/Login', [
            'turnstile_sitekey' => config('turnstile.sitekey'),
        ]);
    }

    public function store(LoginRequest $request): RedirectResponse
    {
        // Validation happens in LoginRequest with TurnstileValidation rule
        $request->authenticate();
        $request->session()->regenerate();

        return redirect()->intended(route('dashboard'));
    }
}

Form Request Example

<?php

namespace App\Http\Requests\Auth;

use DanieleDeSantis\LaravelTurnstile\Http\Rules\TurnstileValidation;
use Illuminate\Foundation\Http\FormRequest;

class LoginRequest extends FormRequest
{
    public function rules(): array
    {
        $rules = [
            'email' => ['required', 'string', 'email'],
            'password' => ['required', 'string'],
        ];

        if (config('turnstile.enabled')) {
            $rules['cf-turnstile-response'] = ['required', 'string', new TurnstileValidation()];
        }

        return $rules;
    }
}

Troubleshooting

Widget Not Displaying

  1. Check that your site key is correct in .env
  2. Verify the script is loading: check browser console for errors
  3. Ensure you are not blocking Cloudflare domains

Verification Always Fails

  1. Check your secret key is correct
  2. Verify the token field name matches (default: cf-turnstile-response)
  3. Check server can reach Cloudflare's API
  4. Review error logs for detailed error codes

Testing Issues

Make sure TURNSTILE_TESTING=true or APP_ENV=testing is set in your test environment.

Error Codes

Cloudflare Turnstile may return the following error codes:

  • missing-input-secret - The secret parameter was not passed
  • invalid-input-secret - The secret parameter was invalid
  • missing-input-response - The response parameter was not passed
  • invalid-input-response - The response parameter is invalid or has expired
  • bad-request - The request was rejected because it was malformed
  • timeout-or-duplicate - The response parameter has already been validated before

Security

If you discover any security-related issues, please email info@danieledesantis.net instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

Support

For support, please open an issue on GitHub or contact info@danieledesantis.net.

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Developed by Daniele De Santis

统计信息

  • 总下载量: 6
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-11-26