Google reCAPTCHA Laravel’de Nasıl Kullanılır?
Google reCAPTCHA kurulumunu Laravel form doğrulama, site key, secret key, backend siteverify isteği, custom validation rule, Blade form ve test örnekleriyle anlatıyorum.
Google reCAPTCHA, Laravel formlarını bot ve spam gönderimlerine karşı korumak için kullanılan pratik bir güvenlik katmanıdır. Ama reCAPTCHA sadece ekrana “Ben robot değilim” kutusu koymak değildir. Frontend tarafında token alınır, backend tarafında Google’ın `siteverify` API’sine bu token doğrulatılır. Asıl güvenlik kontrolü Laravel tarafında yapılmalıdır.
Bu rehberde Laravel’de Google reCAPTCHA nasıl kullanılır adım adım anlatacağım. Örnek olarak iletişim formu kuracağız. Site key ve secret key ayarı, `.env`, config, custom validation rule, controller, Blade form, hata mesajları, v2/v3 farkı ve test yaklaşımı dahil olacak.
reCAPTCHA v2 mi v3 mü?
Google reCAPTCHA tarafında en çok kullanılan iki yaklaşım var:
- reCAPTCHA v2 Checkbox: Kullanıcı “Ben robot değilim” kutusunu görür. Başlangıç için en anlaşılır yöntemdir.
- reCAPTCHA v3: Kullanıcıya kutu göstermez, arka planda skor üretir. Daha sessizdir ama skor yorumlama ve aksiyon mantığı gerekir.
Bu yazıda ana örnek olarak v2 checkbox kullanacağız. Çünkü Laravel form doğrulama mantığını anlatmak için daha net. Yazının sonunda v3 için farkları da göstereceğim.
1. Google reCAPTCHA Key Alma
Önce Google reCAPTCHA admin panelinden site kaydı oluşturmak gerekir:
https://www.google.com/recaptcha/admin/create
Formda şunları seç:
- Label: Proje adın. Örneğin `BodrumDev Contact Form`.
- reCAPTCHA type: Challenge v2 veya “I’m not a robot” Checkbox.
- Domains: Lokal test için `localhost`, canlı için kendi domainin. Örneğin `example.com`.
Kayıt sonrası iki anahtar verir:
- Site key: Frontend/Blade tarafında kullanılır.
- Secret key: Sadece backend/Laravel tarafında kullanılır. Public edilmez.
2. .env Ayarları
Laravel projesinde `.env` dosyasına şunları ekle:
RECAPTCHA_SITE_KEY=site_key_buraya
RECAPTCHA_SECRET_KEY=secret_key_buraya
Secret key’i asla Blade içine yazma, JavaScript’e basma, GitHub’a gönderme. Bu anahtar backend sırrıdır.
3. config/services.php Ayarı
`config/services.php` içine reCAPTCHA ayarını ekleyelim:
'recaptcha' => [
'site_key' => env('RECAPTCHA_SITE_KEY'),
'secret_key' => env('RECAPTCHA_SECRET_KEY'),
],
Config cache kullanıyorsan değişiklikten sonra temizle:
php artisan config:clear
4. İletişim Formu Route ve Controller
Controller oluşturalım:
php artisan make:controller ContactController
`routes/web.php`:
use App\Http\Controllers\ContactController;
use Illuminate\Support\Facades\Route;
Route::get('/iletisim', [ContactController::class, 'create'])
->name('contact.create');
Route::post('/iletisim', [ContactController::class, 'store'])
->middleware('throttle:5,1')
->name('contact.store');
`throttle:5,1` aynı IP’den bir dakikada çok fazla deneme yapılmasını sınırlar. reCAPTCHA tek başına yeterli değildir; rate limit ile birlikte kullanmak daha mantıklı olur.
5. Custom Validation Rule Oluştur
reCAPTCHA doğrulamasını controller içine gömmek yerine custom validation rule yazalım:
php artisan make:rule RecaptchaRule
`app/Rules/RecaptchaRule.php`:
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Facades\Http;
class RecaptchaRule implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (blank($value)) {
$fail('Lütfen reCAPTCHA doğrulamasını tamamlayın.');
return;
}
$response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [
'secret' => config('services.recaptcha.secret_key'),
'response' => $value,
'remoteip' => request()->ip(),
]);
if (! $response->successful()) {
$fail('reCAPTCHA servisine ulaşılamadı. Lütfen tekrar deneyin.');
return;
}
if (! $response->json('success')) {
$fail('reCAPTCHA doğrulaması başarısız oldu.');
}
}
}
Burada Laravel backend tarafında Google’a istek atıyor. Kullanıcıdan gelen `g-recaptcha-response` değeri Google tarafından doğrulanmazsa form geçmiyor.
6. Controller İçinde Kullanım
`app/Http/Controllers/ContactController.php`:
<?php
namespace App\Http\Controllers;
use App\Rules\RecaptchaRule;
use Illuminate\Http\Request;
class ContactController extends Controller
{
public function create()
{
return view('contact.create');
}
public function store(Request $request)
{
$validated = $request->validate([
'name' => ['required', 'string', 'max:120'],
'email' => ['required', 'email', 'max:160'],
'message' => ['required', 'string', 'min:10', 'max:3000'],
'g-recaptcha-response' => ['required', new RecaptchaRule()],
], [
'g-recaptcha-response.required' => 'Lütfen reCAPTCHA doğrulamasını yapın.',
]);
// Burada mesajı veritabanına kaydedebilir veya mail gönderebilirsin.
return back()->with('status', 'Mesajınız alındı. En kısa sürede dönüş yapacağız.');
}
}
Alan adı garip görünebilir: Google frontend tarafında token’ı `g-recaptcha-response` adıyla gönderir. Laravel validation içinde bu alanı kontrol ediyoruz.
7. Blade Form İçine reCAPTCHA Ekle
`resources/views/contact/create.blade.php`:
<!doctype html>
<html lang="tr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>İletişim</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
@if (session('status'))
<p>{{ session('status') }}</p>
@endif
<form method="POST" action="{{ route('contact.store') }}">
@csrf
<div>
<label>Ad Soyad</label>
<input type="text" name="name" value="{{ old('name') }}">
@error('name') <p>{{ $message }}</p> @enderror
</div>
<div>
<label>E-posta</label>
<input type="email" name="email" value="{{ old('email') }}">
@error('email') <p>{{ $message }}</p> @enderror
</div>
<div>
<label>Mesaj</label>
<textarea name="message">{{ old('message') }}</textarea>
@error('message') <p>{{ $message }}</p> @enderror
</div>
<div class="g-recaptcha" data-sitekey="{{ config('services.recaptcha.site_key') }}"></div>
@error('g-recaptcha-response')
<p>{{ $message }}</p>
@enderror
<button type="submit">Gönder</button>
</form>
</body>
</html>
Bu noktada form açıldığında reCAPTCHA kutusu görünür. Kullanıcı doğrulamayı yapıp formu gönderir. Laravel backend tarafında token’ı Google’a doğrulatır.
8. Localhost Testi
Google reCAPTCHA admin panelinde domain olarak `localhost` eklediysen localde test edebilirsin. Laravel sunucusunu çalıştır:
php artisan serve
Tarayıcıda aç:
http://127.0.0.1:8000/iletisim
Eğer reCAPTCHA görünmüyorsa şunları kontrol et:
- `RECAPTCHA_SITE_KEY` doğru mu?
- Google admin panelinde domain doğru mu?
- Script sayfaya yükleniyor mu?
- Tarayıcı console’da hata var mı?
- Config cache temizlendi mi?
9. reCAPTCHA v3 Kısaca Nasıl Farklı?
v3 görünmez çalışır ve `score` döner. Skor 0 ile 1 arasındadır. 1’e yakın değer daha güvenilir, 0’a yakın değer daha şüpheli kabul edilir. Backend tarafında `success` yanında `score` kontrolü de yapılır.
if (! $response->json('success') || $response->json('score') < 0.5) {
$fail('reCAPTCHA doğrulaması başarısız oldu.');
}
v3 için frontend tarafında token genelde JavaScript ile alınır ve hidden input içine yazılır. v2 daha görünür ve başlangıç için daha basittir.
10. Test Yazarken Google’a Gerçek İstek Atma
Testlerde Google API’ye gerçek istek atmak doğru değildir. Laravel’in HTTP fake özelliğini kullanabilirsin.
use Illuminate\Support\Facades\Http;
public function test_contact_form_passes_with_valid_recaptcha(): void
{
Http::fake([
'https://www.google.com/recaptcha/api/siteverify' => Http::response([
'success' => true,
], 200),
]);
$response = $this->post(route('contact.store'), [
'name' => 'Test Kullanıcı',
'email' => 'test@example.com',
'message' => 'Bu test mesajıdır.',
'g-recaptcha-response' => 'fake-token',
]);
$response->assertSessionHasNoErrors();
}
Başarısız doğrulama testi:
public function test_contact_form_fails_with_invalid_recaptcha(): void
{
Http::fake([
'https://www.google.com/recaptcha/api/siteverify' => Http::response([
'success' => false,
], 200),
]);
$response = $this->post(route('contact.store'), [
'name' => 'Test Kullanıcı',
'email' => 'test@example.com',
'message' => 'Bu test mesajıdır.',
'g-recaptcha-response' => 'fake-token',
]);
$response->assertSessionHasErrors('g-recaptcha-response');
}
11. Güvenlikte Dikkat Edilecekler
- Secret key sadece backend tarafında kullanılmalı.
- Formda CSRF token mutlaka olmalı.
- reCAPTCHA yanında rate limit kullanılmalı.
- Backend doğrulaması yapılmadan sadece frontend’e güvenilmemeli.
- Config cache sonrası `.env` değişiklikleri için `php artisan config:clear` çalıştırılmalı.
- Contact form kayıtları spam kontrolü için loglanabilir.
- Çok hassas formlarda IP, user agent ve tekrar gönderim kontrolü eklenebilir.
12. Sık Hatalar
reCAPTCHA kutusu görünmüyor: Site key yanlış olabilir, script yüklenmiyor olabilir veya domain Google panelinde kayıtlı değildir.
Doğrulama hep başarısız: Secret key yanlış olabilir veya frontend’den `g-recaptcha-response` gelmiyor olabilir.
Localde çalışıyor canlıda çalışmıyor: Canlı domain Google reCAPTCHA admin paneline eklenmemiş olabilir.
.env değiştirdim ama düzelmedi: Config cache olabilir. `php artisan config:clear` çalıştır.
Botlar hâlâ geliyor: reCAPTCHA tek başına mucize değildir. Throttle, honeypot, IP kontrolü ve form logları ile desteklemek gerekir.
Kısa Özet
RECAPTCHA_SITE_KEY=...
RECAPTCHA_SECRET_KEY=...
php artisan make:rule RecaptchaRule
Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [
'secret' => config('services.recaptcha.secret_key'),
'response' => $value,
'remoteip' => request()->ip(),
]);
Sonuç
Laravel’de Google reCAPTCHA kullanırken en önemli nokta şudur: frontend sadece token üretir, gerçek doğrulama backend tarafında yapılır. `g-recaptcha-response` alanını alıp Google `siteverify` endpoint’ine göndermeden formu güvenli saymamalısın.
İyi bir form güvenliği için reCAPTCHA, CSRF, validation, rate limit ve loglama birlikte düşünülmelidir. Böyle kurulduğunda Laravel iletişim formları, teklif formları ve yorum formları spam gönderimlerine karşı çok daha dayanıklı olur.
Kaynak notu: Bu yazı Google reCAPTCHA siteverify API mantığı ve Laravel 12 validation/HTTP client yaklaşımı temel alınarak hazırlanmıştır.