Ngày 28/09/2022, Cloudflare đã thông báo về phiên bản beta mở của Turnstile, một giải pháp thay thế vô hình cho CAPTCHA.

Bất kỳ ai, ở bất kỳ đâu trên Internet muốn thay thế CAPTCHA trên trang web của họ đều có thể gọi một API đơn giản mà không cần phải là khách hàng của Cloudflare hoặc gửi lưu lượng truy cập qua mạng toàn cầu của Cloudflare.

Không ích gì khi nhắc lại thực tế rằng CAPTCHA mang lại trải nghiệm tồi tệ cho người dùng, nó đã được thảo luận chi tiết trước đây trên blog này và vô số lần ở những nơi khác. 

Người tạo ra CAPTCHA thậm chí còn công khai than thở rằng anh ta "đã vô tình tạo ra một hệ thống đang lãng phí các tài nguyên quý giá nhất".

Sau khi, chúng ta đã tìm hiểu vì sao Turnstile được ra đời, thì trong bài viết này mình sẽ hướng dẫn các bạn cách sử dụng Turnstile trong dự án Laravel của mình nha.

Khởi tạo dự án Laravel sử dụng Turnstile CAPTCHA 

Đầu tiên, chúng ta cần tạo một dự án Laravel mới, sử dụng lệnh sau: 

composer create-project --prefer-dist laravel/laravel laravel_turnstile

Bạn hãy sử dụng lệnh sau để khởi tạo một controller mới:

php artisan make:controller TurnstileController

Sau khi TurnstileController được khởi tạo, bạn hãy mở và chỉnh sửa như sau:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TurnstileController extends Controller
{
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'name'     => 'required|max:255',
            'email'    => 'required|max:255',
            'password' => 'required|max:255',
        ]);
        //
    }
}

Tiếp theo, bạn hãy mở web.php nằm trong thư mục routes và chỉnh sửa như sau:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TurnstileController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});
Route::resource('users', TurnstileController::class)->only(['store']);

Cuối cùng, chúng ta hãy mở welcome.php nằm trong thư mục resources\views và chỉnh sửa như sau:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Cloudflare's Turnstile CAPTCHA in Laravel</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
    <div class="jumbotron-custom">
        <div class="container text-center">
            <a href="">
                <img src="https://manhdandev.com/web/img/logo.webp" alt="ManhDanBlogs" height="150">
            </a>
            <h1>Cloudflare's Turnstile CAPTCHA in Laravel</h1>
        </div>
    </div>
    <div class="container mt-3">
        <form action="{{ route('users.store') }}" method="POST">
            @csrf
            <div class="mb-3 mt-3">
                <label for="name">Name:</label>
                <input type="name" class="form-control" id="name" placeholder="Enter name" name="name">
                @error('name')
                    <p class="text-danger">{{ $message }}</p>
                @enderror
            </div>
            <div class="mb-3 mt-3">
                <label for="email">Email:</label>
                <input type="email" class="form-control" id="email" placeholder="Enter email" name="email">
                @error('email')
                    <p class="text-danger">{{ $message }}</p>
                @enderror
            </div>
            <div class="mb-3">
                <label for="password">Password:</label>
                <input type="password" class="form-control" id="password" placeholder="Enter password" name="password">
                @error('password')
                    <p class="text-danger">{{ $message }}</p>
                @enderror
            </div>
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>
</body>
</html>

Đăng kí Turnstile CAPTCHA trên Cloudflare 

Đầu tiên, bạn phải tạo tài khoản Cloudflare tại đây. 

Bước 1: Sau khi tạo khoản cloudflare, bạn hãy đăng nhập và chọn mục "Turnstile" như sau:

Bước 2: Nhấn nút "Add Site" và điền thông tin tương tự như sau:

Bước 3: Nhấn nút "Create" để nhận Site KeySecret Key:

Triển khai Turnstile CAPTCHA trong dự án Laravel

Sau khi có thông tin Site KeySecret Key, chúng ta hãy thêm thông tin đó vào .env của Laravel như sau:

TURNSTILE_SITE_KEY=xxxxxxxx
TURNSTILE_SECRET_KEY=xxxxxxxx

Bạn hãy mở services.php nằm trong thư mục configs và thêm đoạn mã nguồn sau:

'turnstile' => [
    'site' => env('TURNSTILE_SITE_KEY'),
    'secret' => env('TURNSTILE_SECRET_KEY'),
],

Tiếp theo, chúng sẽ tạo một custom rule để kiểm tra response có hợp lệ hay không, bằng cách sử dụng lệnh sau:

php artisan make:rule Turnstile

Sau khi khởi tạo custom rule xong, bạn hãy mở Turnstile.php và thêm mã nguồn xử lý như sau:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Http;

class Turnstile implements Rule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {

    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $response = Http::withHeaders([
            'Accept' => 'application/json',
        ])->asForm()->post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
            'secret'   => config('services.turnstile.secret'),
            'response' => $value,
            'remoteip' => $this->getIpClient()
        ]);
        $outcome = $response->json();
        return $outcome['success'] ?? false;
    }

     /**
     * Get the IP Client.
     *
     * @return string
     */
    private function getIpClient() {
        foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
            if (array_key_exists($key, $_SERVER) === true){
                foreach (explode(',', $_SERVER[$key]) as $ip){
                    $ip = trim($ip);
                    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
                        return $ip;
                    }
                }
            }
        }
        return request()->ip();
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
       return 'Our system recognizes you as a Robot.';
    }
}

Khi xây dựng custom rule Turnstile.php hoàn chỉnh, chúng ta sẽ thêm nó vào validation của TurnstileController.php như sau:

<?php

namespace App\Http\Controllers;

...
use App\Rules\Turnstile;

class TurnstileController extends Controller
{
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            ...
            'cf-turnstile-response' => ['required', new Turnstile()]
        ]);
        //
    }
}

Cuối cùng,chúng ta sẽ thêm các mã nguồn để tạo response của Turnstile vào welcome.php nằm trong thư mục resources\views như sau:

<!DOCTYPE html>
<html lang="en">
...
<body>
    ...
    <div class="container mt-3">
        <form action="{{ route('users.store') }}" method="POST">
            @csrf
            ...
            <div class="cf-turnstile text-center" data-sitekey="{{ config('services.turnstile.site') }}"></div>
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>
    <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</body>
</html>

Trải nghiệm Turnstile CAPTCHA trong Laravel

Bạn hãy truy cập vào trang http://127.0.0.1:8000

Để trải nghiệm Turnstile CAPTCHA trong dự án Laravel của mình nào 🌈☀️🌙⭐️🌖🦝

Tài liệu tham khảo:

https://blog.cloudflare.com/turnstile-private-captcha-alternative/

CÓ THỂ BẠN QUAN TÂM

How To Optimize Your Site With GZIP Compression

How To Optimize Your Site With GZIP Compression

GZIP là công nghệ nén thường được sử dụng để truyền dữ liệu một cách nhanh chóng qua Insternet. Hiện nay, GZIP là một tiêu chuẩn để nén các file trên trang web, đa số các website hiện nay hơn 99% sử d...

Integrating CKFinder into CKEditor 5 in Laravel 11

Integrating CKFinder into CKEditor 5 in Laravel 11

CKEditor 5 CKEditor 5 là một trình soạn thảo văn bản phong phú JavaScript với nhiều tính năng và khả năng tùy chỉnh. CKEditor 5 có kiến trúc MVC hiện đại, mô hình dữ liệu tùy chỉnh và DOM ảo, mang...

Integrating TinyMCE in Laravel 10 using Vite

Integrating TinyMCE in Laravel 10 using Vite

TinyMCE TinyMCE là một trình soạn thảo WYSIWYG được xây dựng trên nền tảng Javascript, được phát triển dưới dạng mã nguồn mở theo giấy phép MIT bởi Tiny Technologies Inc. TinyMCE cho phép ngư...

Laravel Socialite Login With Github

Laravel Socialite Login With Github

GitHub GitHub là một nền tảng phát triển phần mềm trực tuyến. Nó được sử dụng để lưu trữ, theo dõi và cộng tác trong các dự án phần mềm. Nó giúp các nhà phát triển dễ dàng chia sẻ các tập tin mã...

Laravel Jobs Batching

Laravel Jobs Batching

Phiên bản Laravel 8 đã được phát hành với một tính năng mà rất nhiều người trong chúng ta đã chờ đợi rất lâu đó là Jobs Batching, nó cho phép chúng ta thực hiện nhiều công việc trong cùng một lúc và t...

Laravel UI Custom Email Verification Template

Laravel UI Custom Email Verification Template

Nếu bạn đang dùng thư viện laravel/ui để làm các chức năng liên quan đến authentication, và trong dự án của bạn, bạn cần thay đổi template email verification thay vì sử dụng template email verificatio...

Laravel Custom Request

Laravel Custom Request

Nếu bạn có một form để người dùng nhập dữ liệu và bạn muốn kiểm tra dữ liệu đầu vào trước khi lưu xuống database chẳng hạn thì bạn có 2 cách sau đây: Cách 1: Bạn thêm validate trực tiếp vào hàm sto...

Efficient Laravel PDF Export for Large Datasets

Efficient Laravel PDF Export for Large Datasets

Xuất file PDF là một tính năng quan trọng của nhiều ứng dụng web, đặc biệt là các trang thương mại điện tử, giúp người dùng tạo và lưu trữ các bản báo cáo, hóa đơn, v.v.  Tuy nhiên, khi phải xử lý...

Laravel Change Expire Time Cookie Remember

Laravel Change Expire Time Cookie Remember

Vấn đề Đôi khi, trang web của bạn chỉ muốn người dùng sử chức năng remembering users  trong 7 ngày hoặc là 30 ngày chẳng hạn. Nhưng Authentication của Laravel không cung cấp cho chúng ta tùy chọn đ...

ManhDanBlogs