12/08/2018, 16:32

Tích hợp Invisible reCaptcha trong ứng dụng Laravel

Invisible reCaptcha là ứng dụng xác thực của Google. Ban đầu Google chỉ phát triển bản reCaptcha thông thường. Sau 2 lần nâng cấp, chúng ta đã có phiên bản APIv3 với có tên gọi Invisible reCaptcha. Bản captcha này khác với các bản reCaptcha trước ở 1 điểm mà mình cho là nó thuận tiện hơn rất ...

Invisible reCaptcha là ứng dụng xác thực của Google. Ban đầu Google chỉ phát triển bản reCaptcha thông thường. Sau 2 lần nâng cấp, chúng ta đã có phiên bản APIv3 với có tên gọi Invisible reCaptcha.

Bản captcha này khác với các bản reCaptcha trước ở 1 điểm mà mình cho là nó thuận tiện hơn rất nhiều. Đó là không cần phải nhập mã xác nhận, hay tích chọn xác nhận mà nó sẽ thực hiện ngầm. Invisible reCaptcha không yêu cầu người dùng phải tự tay click chuột hay nhập liệu gì như kiểu reCaptcha cổ điển. Do đó, nó có tên gọi là Invisible reCaptcha. Đây là 3 phiên bản reCaptcha của Google: reCaptcha v1 reCaptcha v2 Invisible reCaptcha

Nó sử dụng máy học và phân tích các rủi ro một cách thông minh để xác định xem khách truy cập là bot hay con người mà không cần sự tham gia của người dùng. Công nghệ này xem xét dựa trên một vài yếu tố như địa chỉ IP của khách truy cập và cách họ tương tác với trang web khi thực hiện các đánh giá.

  • Khi website của bạn cho phép người dùng gửi thông tin lên server thì nên sử dụng để xác thực và tránh trường hợp bị spam. Có thể dùng ở các form đăng ký tài khoản, download file, comment… tránh gây hao tốn tài nguyên máy chủ.
  • Trước khi sử dụng dịch vụ này, bạn cần đăng ký với Google tại đường dẫn: https://www.google.com/recaptcha/admin#list.
  • Sau khi đăng ký xong, bạn sẽ có key, secret như thế này. Các thông số này mình sẽ lưu vào file .env cho tiện sử dụng:
GOOGLE_CAPTCHA_SECRET=6LcUAjsUAAAAANSzgYCv2L0QVPRMv94vbcBro8Qc
GOOGLE_CAPTCHA_KEY=6LcUAjsUAAAAAL3G8sgsuP_-bjLpVIbjMu7GIJTs
GOOGLE_CAPTCHA_VERIFY_LINK=https://www.google.com/recaptcha/api/siteverify

Chúng ta bắt đầu tích hợp nó vào Laravel nào.

1. Thêm thư viện Thêm thư viện reCaptcha vào trong cặp thẻ <head></head> File blade.php

<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script>
    function onSubmit(token) {
        $('#download-form').submit();
   }
</script>

2. Thêm nút submit kèm tính năng xác thực vào form. File blade.php

{{ Form::open(['url' => route('ebooks.download', $ebook->id), 'method' => 'POST', 'id' => 'download-form']) }}
        <button class="g-recaptcha btn btn-lg btn-primary " data-sitekey="{{ env('GOOGLE_CAPTCHA_KEY') }}" data-callback="onSubmit">
            <i class="fa fa-cloud-download"></i> Tải về
        </button>
{{ Form::close() }}

Sau khi thêm những thứ cần thiết, bạn sẽ thấy ở góc phải màn hình có biểu tượng của reCaptcha với dòng chữ "protected by reCaptcha", tức là bạn đã tích hợp thành công Invisible reCaptcha.

3. Kiểm tra xem CAPTCHA có được xác thực thành công hay không? Khi giao diện đã lên hình rồi, và khi người dùng nhấn vào nút submit "Tải về" kia thì form của chúng ta sẽ truyền lên các params, trong đó có param quan trọng dùng để xác thực. Đó là: g-recaptcha-response. Giá trị của param g-recaptcha-response như các bạn thấy trên hình là 1 đống ký tự loằng ngoằng. Nó là dữ liệu mà chúng ta sẽ dùng để gửi tới API của reCaptcha để xác nhận xem hành động này có hợp lệ hay không, có phải spam hay không. API Request URL: https://www.google.com/recaptcha/api/siteverify. Chi tiết API xác thực này, bạn có thể xem tại đây. Chúng ta sẽ cần viết 1 hàm có nhiệm vụ tương tác tới API trên để lấy về kết quả xác thực. Ở đây các bạn có thể dùng nhiều cách khác nhau để gọi API, có thể sử dụng Guzzle HTTP. Trong ví dụ này mình sẽ sử dụng CURL của PHP. Controller

public function verifyCaptcha($params)
{
    $verifyUrl = env('GOOGLE_CAPTCHA_VERIFY_LINK', 'https://www.google.com/recaptcha/api/siteverify');
    $ch = curl_init($verifyUrl);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_POST, count($params));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec ($ch);
    curl_close ($ch);
    return $result;
}

Việc của chúng ta là truyền 2 params bắt buộc đó là secret và response. Sau đó việc xác thực là của Google. Chúng ta không cần quan tâm đến việc này mà chỉ cần quan tâm đến dữ liệu JSON trả về kết quả.

Bạn có thể thấy giá trị success nhận về trong ví dụ của mình là true, tức là việc xác thực form là hợp lệ. Nếu success là false thì đã có lỗi xác thực. Chúng ta căn cứ vào kết quả xác thực để quyết định có thực hiện tiếp hành động submit form nữa không hay là báo lỗi và back lại. Controller

public function download($id, Request $request)
{
    if ($request->isMethod('post')) {
            $params = $request->all();
            $captchaParams = [
                'secret' => env('GOOGLE_CAPTCHA_SECRET'),
                'response' => $params['g-recaptcha-response']
            ];
            $verifyCaptcha = json_decode($this->verifyCaptcha($captchaParams));

            if(!$verifyCaptcha->success) {
                return view('ebooks.download')
                    ->withErrors(['Lỗi xác thực']);
            }
            // Xác thực thành công, thực hiện hành động tiếp theo.
            return 'Success';
    }
}

Trong ví dụ này của mình, nếu xác thực thành công, mình sẽ cho phép người dùng download file về máy. Nếu không, mình sẽ báo lỗi như thế này: Dưới đây là toàn bộ source code của mình, các bạn có thể tham khảo. .env

GOOGLE_CAPTCHA_SECRET=6LcUAjsUAAAAANSzgYCv2L0QVPRMv94vbcBro8Qc
GOOGLE_CAPTCHA_KEY=6LcUAjsUAAAAAL3G8sgsuP_-bjLpVIbjMu7GIJTs
GOOGLE_CAPTCHA_VERIFY_LINK=https://www.google.com/recaptcha/api/siteverify

routes/web.php

Route::get('ebooks/download/{id}', 'EbooksController@download')
        ->where(['id' => '[0-9]+'])
        ->name('ebooks.download');

app/Http/Controller/EbooksController.php

namespace AppHttpControllers;

use AppHttpControllersController;

class EbooksController extends Controller 
{
    public function download($id, Request $request)
    {
        if ($request->isMethod('post')) {
                $params = $request->all();
                $captchaParams = [
                    'secret' => env('GOOGLE_CAPTCHA_SECRET'),
                    'response' => $params['g-recaptcha-response']
                ];
                $verifyCaptcha = json_decode($this->verifyCaptcha($captchaParams));

                if(!$verifyCaptcha->success) {
                    return view('ebooks.download')
                        ->withErrors(['Lỗi xác thực']);
                }
                // Xác thực thành công, thực hiện hành động tiếp theo.
                return 'Success';
        }
        
        public function verifyCaptcha($params)
        {
            $verifyUrl = env('GOOGLE_CAPTCHA_VERIFY_LINK', 'https://www.google.com/recaptcha/api/siteverify');
            $ch = curl_init($verifyUrl);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_POST, count($params));
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $result = curl_exec ($ch);
            curl_close ($ch);
            return $result;
        }
    }
}

resources/views/ebooks/download.blade.php

<html>
  <head>
    <title>reCAPTCHA demo: Simple page</title>
     <script src="https://www.google.com/recaptcha/api.js" async defer></script>
     <script>
       function onSubmit(token) {
            $('#download-form').submit();
       }
     </script>
  </head>
  <body>
      @if ($errors->any())
          <div class="alert alert-danger">
              <ul>
                  @foreach ($errors->all() as $error)
                      <li>{{ $error }}</li>
                  @endforeach
              </ul>
         </div>
    @endif
    {{ Form::open(['url' => route('ebooks.download', $ebook->id), 'method' => 'POST', 'id' => 'download-form']) }}
            <button class="g-recaptcha btn btn-lg btn-primary " data-sitekey="{{ env('GOOGLE_CAPTCHA_KEY') }}" data-callback="onSubmit">
                <i class="fa fa-cloud-download"></i> Tải về
            </button>
    {{ Form::close() }}
  </body>
</html>

Như vậy, mình đã giới thiệu đến các bạn cách tích hợp công cụ Invisible reCaptcha vào trong project Laravel. Theo mình thì nó rất hữu ích cho chúng ta trong quá trình cần xác thực dữ liệu nhằm tránh spam. Hi vọng, bài viết của mình sẽ giúp ích được cho các bạn. Cám ơn các bạn đã đọc bài viết!

https://developers.google.com/recaptcha/docs/invisible#auto_render https://developers.google.com/recaptcha/docs/verify https://tinhoccnm.com/invisible-recaptcha/

0