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
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 Turnstilecomponents/Turnstile.tsx- React component for Turnstileindex.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.
- Go to Cloudflare Dashboard
- Navigate to Turnstile in the sidebar
- Click Add Site
- Enter your domain name
- Choose widget mode (recommended: Managed)
- 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, ordark(default:auto)size:normal,compact, orflexible(default:normal)field-name: Custom field name (default:cf-turnstile-response)callback: JavaScript callback function nameerror-callback: Error callback function nameexpired-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
- Check that your site key is correct in
.env - Verify the script is loading: check browser console for errors
- Ensure you are not blocking Cloudflare domains
Verification Always Fails
- Check your secret key is correct
- Verify the token field name matches (default:
cf-turnstile-response) - Check server can reach Cloudflare's API
- 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 passedinvalid-input-secret- The secret parameter was invalidmissing-input-response- The response parameter was not passedinvalid-input-response- The response parameter is invalid or has expiredbad-request- The request was rejected because it was malformedtimeout-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
其他信息
- 授权协议: MIT
- 更新时间: 2025-11-26