📜 ⬆️ ⬇️

Connecting Google reCAPTCHA to Vue and validating the response on the server


In this article, I will show how to connect Google's captcha (reCAPTCHA) on Vue JS and validate the response on the server (I use the Laravel / Lumen backend as an example, but the principle of validation is the same for all technologies).


Foreword


We will use Invisible reCAPTCHA .
This is an invisible * captcha that you don’t need to go through until the system considers it necessary. The site administrator can set a Security Preference threshold level at which the system will require the user to undergo additional testing.


* - the reCAPTCHA icon must still be present on the page.



Invisible captcha on the site.


Question answer


Before starting work, I would like to answer the questions I had when I started working with Google reCAPTCHA.


Q: How much does reCAPTCHA cost?
A: Google's ReCAPTCHA is a free tool.


Q: Why do I need to once again check the user's answer on the backend if he has already passed the captcha on the site?
A: When you make a request to the server, you send something like this:


POST /register 1.1 HTTP Host: www.example.com { "email:"user@gmail.com", "password": "supersecret", "recaptcha-token":"01ASJASJFZ_AASD3115..." } 

If you do not check the captcha token on the backend, bots can simply spam with requests WITHOUT this token or replace it with a dummy one.


Q: I have a reactor, what should I do?
A: React JS is a great thing. If you use it to develop websites, I advise you to pay attention to https://github.com/appleboy/react-recaptcha . The principle of operation is very similar to the example with Vue.


Getting Started


So, before you start cooking, we need a list of ingredients:



Step # 1: Get the keys to use reCAPTCHA on your site


We need to get the site key and secret key on Google: https://www.google.com/recaptcha/admin#list



In the label field you can write anything.


Next, select the type - Invisible reCAPTCHA badge .


You can specify several domains on which you will use captcha.
As an example, I specified yourawesomedomain.com and localhost .


Accept the terms of use and move on.



You were given two keys, keep them in a safe place. We will return to them later.


Step 2: Frontend. Install and connect captcha to our forms


First, we need to add this code to the head section:


 <script src="https://www.google.com/recaptcha/api.js?onload=vueRecaptchaApiLoaded&render=explicit" async defer></script> 

The onload property will tell our component that the captcha is ready for use.


Then I will show the finished component and we will analyze it in parts:


 <template> <div id="app"> <div class="container my-4"> <div class="row justify-content-center"> <div class="col-md-8"> <h2 class="text-center mb-4"> Sign Up Form with Google reCAPTCHA </h2> <form method="post" @submit.prevent="validate"> <div class="form-group"> <input type="email" name="email" class="form-control" placeholder="Enter your e-mail address" required /> </div> <div class="form-group"> <input type="password" name="password" class="form-control" placeholder="Enter your password" required /> </div> <div class="form-group"> <vue-recaptcha ref="recaptcha" size="invisible" :sitekey="sitekey" @verify="register" @expired="onCaptchaExpired" /> <button type="submit" class="btn btn-primary btn-block"> Sign Up </button> </div> </form> </div> </div> </div> </div> </template> <script> import VueRecaptcha from 'vue-recaptcha' export default { name: 'Register', components: { VueRecaptcha }, data () { return { email: null, password: null, sitekey: ' SITE KEY' } }, methods: { register (recaptchaToken) { axios.post('https://yourserverurl.com/register', { email: this.email, password: this.password, recaptchaToken: recaptchaToken }) }, validate () { //       // ,   vee validate //       ,   this.$refs.recaptcha.execute() }, onCaptchaExpired () { this.$refs.recaptcha.reset() } } } </script> 

Example component using VeeValidate to validate fields
 <template> <div id="app"> <div class="container my-4"> <div class="row justify-content-center"> <div class="col-md-8"> <h2 class="text-center mb-4"> Sign Up Form with Google reCAPTCHA </h2> <form method="post" @submit.prevent="validate"> <div class="form-group"> <input type="email" name="email" class="form-control" placeholder="Enter your e-mail address" v-validate.disable="'required|email'" required /> <div v-show="errors.has('email')" class="invalid-feedback d-block" > {{ errors.first('email') }} </div> </div> <div class="form-group"> <input type="password" name="password" class="form-control" placeholder="Enter your password" v-validate.disable="'required|min:6|max:32'" required /> <div v-show="errors.has('password')" class="invalid-feedback d-block" > {{ errors.first('password') }} </div> </div> <div class="form-group"> <vue-recaptcha ref="recaptcha" size="invisible" :sitekey="sitekey" @verify="register" @expired="onCaptchaExpired" /> <button type="submit" class="btn btn-primary btn-block"> Sign Up </button> </div> </form> </div> </div> </div> </div> </template> <script> import VueRecaptcha from 'vue-recaptcha' export default { name: 'Register', components: { VueRecaptcha }, data () { return { email: null, password: null, sitekey: ' SITE KEY' } }, methods: { register (recaptchaToken) { axios.post('https://yourserverurl.com/register', { email: this.email, password: this.password, recaptchaToken: recaptchaToken }) }, validate () { const self = this self.$validator.validateAll().then((result) => { if (result) { self.$refs.recaptcha.execute() } }) }, onCaptchaExpired () { this.$refs.recaptcha.reset() } } } </script> 

Let's start with the fact that we have imported Vue-Recaptcha into our component:


 import VueRecaptcha from 'vue-recaptcha' ... components: { VueRecaptcha }, 

Next we declared the sitekey property in the data () component:


 data () { return { ... sitekey: ' SITE KEY' } }, 

Add the Vue-Recaptcha component to our form:


 <vue-recaptcha ref="recaptcha" size="invisible" :sitekey="sitekey" @verify="register" @expired="onCaptchaExpired" /> 

The register method will be called when a captcha passes successfully, while expired is called when a captcha expires.


The onCaptchaExpired method restarts the captcha:


 onCaptchaExpired () { this.$refs.recaptcha.reset() } 

To the form itself, we add the @ submit.prevent = "validate" event, which runs the validate method when the form is submitted .


 validate () { this.$refs.recaptcha.execute() } 

The process can be described as:


  1. The user entered the data and clicked the Sign Up button, the validate () function is called.
  2. The validate () function starts a captcha; if the user successfully passes it, the register method is called.

In the register method, we get the recaptchaToken , which we must send to the server along with the data entered by the user:


 register (recaptchaToken) { axios.post('https://yourserverurl.com/register', { email: this.email, password: this.password, recaptchaToken: recaptchaToken }) } 

This is where our front-end work is done. ReCAPTCHA successfully installed and running.


PS If you are going to use captcha in several components, it is best to place sitekey in an .env file and receive it using process.env :


 data () { return { ... sitekey: process.env.VUE_APP_RECAPTCHA_TOKEN } }, 

Step 3: Validation on the backend. Laravel and Lumen Validation Example


Making a response validation on the server is very easy. Let's start with an example on Laravel.


1) In the config folder, create a file recaptcha.php with the following contents:


 <?php return [ 'enabled' => env('RECAPTCHA_ENABLED', true), 'key' => env('RECAPTCHA_SITE_KEY'), 'secret' => env('RECAPTCHA_SECRET_KEY'), ]; 

2) After that, add variables to the .env file:


 RECAPTCHA_ENABLED=FALSE RECAPTCHA_SITE_KEY=_SITE_KEY RECAPTCHA_SECRET_KEY=_SECRET_KEY 

3) Install GuzzleHttp to be able to send requests to the Google API:


 composer require guzzlehttp/guzzle 

4) In the controller, add the checkRecaptcha method:


 protected function checkRecaptcha($token, $ip) { $response = (new Client)->post('https://www.google.com/recaptcha/api/siteverify', [ 'form_params' => [ 'secret' => config('recaptcha.secret'), 'response' => $token, 'remoteip' => $ip, ], ]); $response = json_decode((string)$response->getBody(), true); return $response['success']; } 

In this method, we send our token (which we received from the front end) using the POST method to https://www.google.com/recaptcha/api/siteverify


5) In the register method (in your case the name may be different, this is the method to which you sent the POST request from the frontend) add the following code:


 if (config('recaptcha.enabled') && !$this->checkRecaptcha($request->recaptcha_token, $request->ip())) { return return response()->json([ 'error' => 'Captcha is invalid.', ], Response::HTTP_BAD_REQUEST); } 

Everything is ready for use!




Journey token. Visual presentation.


The full controller code will look like this:


 <?php namespace App\Http\Controllers\Users; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Http\Response; use GuzzleHttp\Client; class UserController extends Controller { protected function checkRecaptcha($token, $ip) { $response = (new Client)->post('https://www.google.com/recaptcha/api/siteverify', [ 'form_params' => [ 'secret' => config('recaptcha.secret'), 'response' => $token, 'remoteip' => $ip, ], ]); $response = json_decode((string)$response->getBody(), true); return $response['success']; } public function register(Request $request) { $request->validate([ 'email' => 'required|string|email|unique:users|max:255', 'password' => 'required|string|max:32|min:6', 'recaptcha_token' => 'string' ]); if (config('recaptcha.enabled') && !$this->checkRecaptcha($request->recaptcha_token, $request->ip())) { return response()->json([ 'error' => 'Captcha is invalid.', ], Response::HTTP_BAD_REQUEST); } //  .  ... } } 

Validation of the response to Lumen


On Lumen, we do everything the same way as in the example with Laravel, except that we need to register our config ( recaptcha.php ) in bootstrap / app.php :


 $app->configure('recaptcha'); 

Conclusion


So, in this article, you learned how to use Google reCAPTCHA in your Vue project.


ReCAPTCHA is a great free tool to protect your resource from bots.
With invisible captcha you can check visitors without requiring any action from them.


Sample application from the article on codepen


Used sources:


  1. https://github.com/DanSnow/vue-recaptcha
  2. https://developers.google.com/recaptcha/docs/invisible
  3. https://developers.google.com/recaptcha/docs/verify
  4. https://security.stackexchange.com/questions/78807/how-does-googles-no-captcha-recaptcha-work

')

Source: https://habr.com/ru/post/443370/


All Articles