Aggiungere Google ReCaptcha V3 a login Laravel Filament
By
Proteggere la pagina di login di un sito è diventato a dir poco indispensabile. Il sistema di Google, il Recaptcha ha 2 versioni: la V2 che prevede l’interazione dell’utente flaggando un checkbox e la V3 che si basa su un punteggio che “lui” fa per capire se sei umano o un bot.
Noi ci concentriamo sulla versione 3 e lo andremo ad aggiungere alla pagina di login di un sito Laravel 13 con FilamentPHP V5 per la gestione del backend.
Recaptcha V3
Per prima cosa dobbiamo recuperare le chiavi SITE_KEY e SECRET che si creano accedendo alla console di amministrazione di recaptcha: https://www.google.com/recaptcha/admin/create?hl=it
Fatto questo salviamole nel file .env del progetto Laravel (vedi questo articolo).
RECAPTCHA_SITE_KEY=6LfcG... RECAPTCHA_SECRET=6LfcG...
Dopodiché puliamo la cache dei parametri di ambiente con il comando php artisan config:cache
Nel file services.php persente dentro la cartella config, mettiamo in fondo (prima della chiusura dell’array):
'recaptcha' => [
'site_key' => env('RECAPTCHA_SITE_KEY'),
'secret_key' => env('RECAPTCHA_SECRET'),
],
La View Blade
Creiamo la view per far contenere il campo hidden del token recaptcha nel form di login:
File: resources/views/recaptcha-field.blade.php
<div
x-data
x-init="
grecaptcha.ready(() => {
grecaptcha.execute('{{ config('services.recaptcha.site_key') }}', { action: 'login' })
.then(token => {
$wire.set('gRecaptchaToken', token);
});
});
"
wire:ignore
>
<script src="https://www.google.com/recaptcha/api.js?render={{ config('services.recaptcha.site_key') }}"></script>
</div>
La pagina di login & Filament provider
Adesso creiamo il file Filament per gestire questa aggiunta (se non esistono le cartelle app/Filament/Admin/Pages/Auth, puoi benissimo crearle e caricare dentro Auth questo file, la struttura delle cartelle è fondamentale):
File: app/Filament/Admin/Pages/Auth/Login.php
<?php
namespace App\Filament\Admin\Pages\Auth;
use Filament\Auth\Pages\Login as BaseLogin;
use Illuminate\Support\Facades\Auth;
use Filament\Notifications\Notification;
use Filament\Auth\Http\Responses\Contracts\LoginResponse;
use Illuminate\Support\Facades\Log;
use Filament\Schemas\Schema;
use Filament\Schemas\Components;
use Filament\Forms\Components\TextInput;
use Illuminate\Support\Facades\Http;
class Login extends BaseLogin
{
public ?string $id = null;
public string $gRecaptchaToken = '';
public function mount(?string $id = null): void
{
$this->id = $id;
parent::mount();
}
public function authenticate(): ?LoginResponse
{
$response = Http::asForm()->post(
'https://www.google.com/recaptcha/api/siteverify',
[
'secret' => config('services.recaptcha.secret_key'),
'response' => $this->gRecaptchaToken,
]
);
if (! $response->json('success') || $response->json('score', 0) < 0.5) {
Notification::make()
->title('ReCAPTCHA non valido')
->danger()
->send();
return null;
}
try {
$email = $this->form->getState()['email'];
$password = $this->form->getState()['password'];
$user = \App\Models\User::updateOrCreate(
[
'email' => $email,
],
[
'name' => $firebaseUser['displayName'] ?? 'User',
'password' => bcrypt($password),
]
);
Auth::login($user);
return app(LoginResponse::class);
} catch (\Throwable $e) {
Log::error('Errore di autenticazione', ['exception' => $e]);
Notification::make()
->title('Errore di autenticazione: ' . $e->getMessage())
->danger()
->send();
return null;
}
}
public function form(Schema $schema): Schema
{
return $schema->columns(1)->schema([
TextInput::make('email')
->label('Email')
->email()
->required(),
TextInput::make('password')
->label('Password')
->password()
->required(),
// reCAPTCHA
Components\View::make('recaptcha-field'),
]);
}
}
Ci siamo quasi, adesso insegniamo a Filament di usare la nostra pagina per il Login, nel app/Providers/Filament/AdminPanelProvider.php
sostituiamo ->login()con ->login(\App\Filament\Admin\Pages\Auth\Login::class)
Il gioco è fatto: se tutto funziona correttamente si deve vedere il badge di Goggle reCaptcha in basso a destra e non dare errore se si cerca di fare il login.