Protect site against spam using Google Recaptcha in Django Framework
Online spam is the most irritating thing which happens to site users. The problem is that you won’t be able to distinguish between a real user and a bot browsing through your site.
There is a solution for such to protect your site is to use Google Recaptcha V3 API which I’ll teach you in this post of how to protect against bots and spams using Google Recaptcha in Django Rest Framework.
Create Project And App in Django
Client-Side Integration
For Client-Side Integration, there are two ways of doing it. But both the ways are a bit different and here we’ll learn about both the ways.
1. Generating token Automatically
Here the captcha will automatically calculate on the basis of score and add the captcha token within the form when the user clicks the button. On the server side, you can access the token by the name g-recaptcha-response.
<script src="https://www.google.com/recaptcha/api.js"></script> <form onsubmit="onSubmit( event )" id="contactus-form" method="post"> <!-- here have your form fields --> <button class="g-recaptcha" data-sitekey="<recaptcha_clientside_secret_here>" data-callback='onSubmit' data-action='submit'>Submit</button> </form> <script> function onSubmit(token) { document.getElementById("contactus-form").submit(); } </script>
2. Generating token Programmatically
In this step, you can decide when to invoke the captcha and receive token and this is also good for the custom requirements if you have any on those.
<script src="https://www.google.com/recaptcha/api.js?render=<recaptcha_clientside_secret_here>"></script> <form onsubmit="onSubmit( event )" id="contactus-form" method="post"> <!-- here you will have response of recaptcha token --> <input type="hidden" name="recaptcha_token" id="recaptcha_token" value="" > <!-- here have your form fields --> <input type="submit" value="Submit"> </form> <script> function onSubmit(e) { e.preventDefault(); grecaptcha.ready(function() { grecaptcha.execute('<recaptcha_clientside_secret_here>', {action: 'submit'}).then(function(token) { // here fetch the token and add to form field document.getElementById('recaptcha_token').value = token; e.target.submit(); }); }); } </script>
Handling Token on Serverside
On the server side, you have to to a cURL request to https://www.google.com/recaptcha/api/siteverify with the serverside secret key.
Here is a sample working code in Python Django Framework.
import requests serverside_secret = "<recaptcha_serverside_secret_here>" url = "https://www.google.com/recaptcha/api/siteverify" query = { "secret" : serverside_secret, "response" : request.POST.get('g-recaptcha-response') #if you are using generating token automatically #OR "response" : request.POST.get('recaptcha_token') #if you are using generating token Programatically } response = requests.post( url, data=query ) response_json = response.json()
The method response.json()
will give you the JSON response and to verify if the response is correct to use the success
key must be True
.
Here is the sample success response in JSON.
{ "success": true, "challenge_ts": "2022-01-12T19:15:43Z", "hostname": "127.0.0.1", "score": 0.9, "action": "submit" }
Here there are two most important keys to look for they are:
- success: This will return
True
if the response value is correct. - score: This ranges from 0 to 1 and 1 being accurate and 0 being considered as bot.
Note
The captcha response will only work once and if you try to send the response with the same token then you will receive a timeout-or-duplicate error and a similar response as shown below.
{ "success": false, "error-codes": [ "timeout-or-duplicate" ] }
Integration Recaptcha with Django Framework
I’ll be using an example of the contact us form where I’ll implement Recaptcha.
In main app src\settings.py
RECAPTCHA = { 'clientside_secret' : 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'serverside_secret' : 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'verify_url' : 'https://www.google.com/recaptcha/api/siteverify' }
In contactus\forms.py
from django import forms import requests from django.conf import settings def recaptcha_validator(value): query = { "secret" : settings.RECAPTCHA['serverside_secret'], "response" : value } response = requests.post( settings.RECAPTCHA['verify_url'], data=query ) response_json = response.json() if response_json['success'] == False: error_str = "".join( response_json['error-codes'] ) raise forms.ValidationError(f"Recaptcha Error : { error_str }") class ContactForm(forms.Form): name = forms.CharField(max_length=255, required=True, initial="", label="Name*", widget=forms.TextInput( attrs={ 'class' : 'form-control' } )) message = forms.CharField(required=False, initial="", label="Message*", widget=forms.Textarea( attrs={ 'class' : 'form-control', 'rows' : 3 } )) phone_no = forms.CharField(required=False, label="Phone no*" , widget=forms.TextInput( attrs={ 'class' : 'form-control' } )) recaptcha_token = forms.CharField( initial="", validators=[recaptcha_validator] )
In contactus\views.py
from django.shortcuts import render, HttpResponse from contactus.forms import ContactForm from django.conf import settings # Create your views here. def form(request): info = { 'form' : ContactForm(), 'recaptcha_setting' : settings.RECAPTCHA } return render(request, 'contactus/form.html', info) def save(request): info = { 'form' : ContactForm(request.POST), 'recaptcha_setting' : settings.RECAPTCHA } if info["form"].is_valid(): return HttpResponse("All fields correct.") return render(request, 'contactus/form.html', info)
In contactus\templates\contactus\form.html
<script src="https://www.google.com/recaptcha/api.js?render={{recaptcha_setting.clientside_secret}}"></script> <div class="row"> <div class="col-md-4 offset-md-4"> {% if form.errors %} <div class="alert alert-danger" > <h4>Form Submission Errors</h4> <ul> {% for index, error in form.errors.items %} {{ error }} {% endfor %} </ul> </div> {% endif %} <h2 class="text-center" >Contact Form</h2> <form onsubmit="onSubmit(event)" action="{% url 'contactus:save' %}" method="post" > {% csrf_token %} {{form.recaptcha_token.as_hidden}} <div> <label>{{ form.name.label }}</label> {{form.name}} </div> <div> <label>{{ form.message.label }}</label> {{form.message}} </div> <div> <label>{{ form.phone_no.label }}</label> {{form.phone_no}} </div> <div class="mt-10" > <input type="submit" class="btn btn-primary btn-block" value="Save"> </div> </form> </div> </div> <script> function onSubmit(e) { e.preventDefault(); grecaptcha.ready(function() { grecaptcha.execute('{{recaptcha_setting.clientside_secret}}', {action: 'submit'}).then(function(token) { document.getElementsByName('recaptcha_token')[0].value = token; e.target.submit(); }); }); } </script>
In contactus\urls.py
from django.urls import path from contactus import views app_name = "contactus" urlpatterns = [ path( 'form', views.form, name="form" ), path( 'save', views.save, name="save" ), ]
Custom Validator to Check to validity
In contactus\forms.py, I have created a custom validator to check whether the captcha token is valid to not, and also this code makes validation simpler and easier.
from django import forms import requests from django.conf import settings def recaptcha_validator(value): query = { "secret" : settings.RECAPTCHA['serverside_secret'], "response" : value } response = requests.post( settings.RECAPTCHA['verify_url'], data=query ) response_json = response.json() if response_json['success'] == False: error_str = "".join( response_json['error-codes'] ) raise forms.ValidationError(f"Recaptcha Error : { error_str }")
Watch Video
Conclusion
This was all about Protect site against spam using Google Recaptcha and Integrating Google Recaptcha in Django Framework. Thank you for reading.