Using Google Captcha with Spring Boot Application

Welcome, in this tutorial, we will see how to implement google captcha (reCAPTCHA v2) in a spring boot web application. reCAPTCHA is a free service that protects an application from spammers. It uses advanced risk analysis techniques to keep humans and bots apart.

1. Introduction

Before going further in this tutorial, we will look at the common terminology such as introduction to Spring Boot and Lombok.

1.1 Spring Boot

1.2 Lombok

1.2.1 Lombok features

Feature Details
val Local variables are declared as final
var Mutable local variables
@Slf4J Creates an SLF4J logger
@Cleanup Will call close() on the resource in the finally block
@Getter Creates getter methods for all properties
@Setter Creates setter for all non-final properties
@EqualsAndHashCode
  • Generates implementations of equals(Object other) and hashCode()
  • By default will use all non-static, non-transient properties
  • Can optionally exclude specific properties
@ToString
  • Generates String of class name, and each field separated by commas
  • Optional parameter to include field names
  • Optional parameter to include a call to the super toString method
@NoArgsConstructor
  • Generates no-args constructor
  • Will cause compiler error if there are final fields
  • Can optionally force, which will initialize final fields with 0/false/null var – mutable local variables
@RequiredArgsContructor
  • Generates a constructor for all fields that are final or marked @NonNull
  • The constructor will throw a NullPointerException if any @NonNull fields are null val – local variables are declared final
@AllArgsConstructor
  • Generates a constructor for all properties of the class
  • Any @NotNull properties will have null checks
@Data
  • Generates typical boilerplate code for POJOs
  • Combines – @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor
  • No constructor is generated if constructors have been explicitly declared
@Builder
  • Implements the Builder pattern for object creation
@Value
  • The immutable variant of @Data
  • All fields are made private and final by default

Let us go ahead with the tutorial implementation but before going any further I’m assuming that you’re aware of the Spring boot basics.

2. Using Google Captcha with Spring Boot Application

2.1 Application Pre-requisite

To obtain the API keys we will need a google account. Navigate to the following URL – https://www.google.com/recaptcha/admin#list for the registration of a new site. Enter the details as shown in Fig. 1 and remember to choose the reCAPTCHA v2. Click submit and once the site is successfully registered, the site and client keys will be generated and will be further used in the tutorial.

Fig. 1: Registering a site

2.2 Tools Used for Spring boot application and Project Structure

We are using Eclipse Kepler SR2, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.

Fig. 2: Project structure

Let us start building the application!

3. Creating a Spring Boot application

Below are the steps involved in developing the application.

3.1 Maven Dependency

Here, we specify the dependency for the Spring boot (Web) and Lombok. Maven will automatically resolve the other dependencies. The updated file will have the following code.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot.google.captcha</groupId>
    <artifactId>SpringbootandGooglecaptcha</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringbootandGooglecaptcha</name>
    <description>Springboot and google captcha</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3.2 Application properties file

Create a new properties file at the location: SpringbootandGooglecaptcha/src/main/resources/ and add the following code to it. Here we will define the application and google reCAPTCHA configuration.

application.properties

# application properties
server.port=9001
# google recaptcha config properties
# these properties will be used in the ValidateCaptcha.java class
google.recaptcha.verification.endpoint=https://www.google.com/recaptcha/api/siteverify
google.recaptcha.secret=YOUR_SECRET_KEY

3.3 Java Classes

Let us write the important java class(es) involved in this application. For brevity, we will skip the following classes –

3.3.1 Implementation/Main class

Add the following code to the main class to bootstrap the application from the main method. Always remember, the entry point of the spring boot application is the class containing @SpringBootApplication annotation and the static main method.

SpringbootandGooglecaptchaApplication.java

package com.springboot.google.captcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// Lombok annotation for logger
@Slf4j
// Spring annotation
@SpringBootApplication
public class SpringbootandGooglecaptchaApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootandGooglecaptchaApplication.class, args);
        log.info("Springboot and google captcha application started successfully.");
    }
}

3.3.2 Captcha response model class

Add the following code to the model class which will be used to map the incoming response from google’s REST API. This class contains –

CaptchaResponse.java

package com.springboot.google.captcha.responsemodel;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.time.LocalDateTime;
import java.util.List;
// Lombok annotations
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class CaptchaResponse {
	boolean success;
	LocalDateTime challenge_ts;
	String hostname;
	@JsonProperty("error-codes")
	List<String> errorCodes;
}

3.3.3 Captcha validator class

Add the following code to the validator class to validate the captcha response coming from the client-side.

ValidateCaptcha.java

package com.springboot.google.captcha.service;
import com.springboot.google.captcha.responsemodel.CaptchaResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.util.Objects;
@Slf4j
@Service
public class ValidateCaptcha {
	private final RestTemplate template;
	@Value("${google.recaptcha.verification.endpoint}")
	String recaptchaEndpoint;
	@Value("${google.recaptcha.secret}")
	String recaptchaSecret;
	public ValidateCaptcha(final RestTemplateBuilder templateBuilder) {
		this.template = templateBuilder.build();
	}
	// method validate the captcha response coming from the client
	// and return either true or false after the validation.
	// reference url - https://developers.google.com/recaptcha/docs/verify
	public boolean validateCaptcha(final String captchaResponse) {
		// "captchaResponse" length validation is omitted for brevity.
		
		log.info("Going to validate the captcha response = {}", captchaResponse);
		final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
		// "secret" is a required param and it represents the shared key between your site 
		// and the recaptcha.
		params.add("secret", recaptchaSecret);
		// "response" is a required param and it represents the user token provided
		// by the recaptcha client-side integration on your site.
		params.add("response", captchaResponse);
		CaptchaResponse apiResponse = null;
		try {
			apiResponse = template.postForObject(recaptchaEndpoint, params, CaptchaResponse.class);
		} catch (final RestClientException e) {
			log.error("Some exception occurred while binding to the recaptcha endpoint.", e);
		}
		if (Objects.nonNull(apiResponse) && apiResponse.isSuccess()) {
			log.info("Captcha API response = {}", apiResponse.toString());
			return true;
		} else {
			return false;
		}
	}
}

3.3.4 Controller class

Add the following code to the controller class. The class is injected with the service dependency whose method will be used to validate the incoming captcha response.

HelloCtrl.java

package com.springboot.google.captcha.controller;
import com.springboot.google.captcha.exception.ForbiddenException;
import com.springboot.google.captcha.model.HelloDto;
import com.springboot.google.captcha.model.HelloResponseDto;
import com.springboot.google.captcha.service.ValidateCaptcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
// Lombok annotation for logger
@Slf4j
// Spring annotations
@RestController
@RequestMapping("/api")
public class HelloCtrl {
 
	// injected to validate the captcha response coming in the request.
    @Autowired
    ValidateCaptcha service;
    // URL - http://localhost:9001/api/welcome
    @PostMapping("/welcome")
    @ResponseStatus(code = HttpStatus.OK)
    public HelloResponseDto welcome(@RequestBody final HelloDto dto)
            throws ForbiddenException {
        final boolean isValidCaptcha = service.validateCaptcha(dto.getCaptchaResponse());
        if (!isValidCaptcha) {
            log.info("Throwing forbidden exception as the captcha is invalid.");
            throw new ForbiddenException("INVALID_CAPTCHA");
        }
        return new HelloResponseDto("Greetings " + dto.getName());
    }
}

3.4 Client-side

As the reCAPTCHA cannot be validated via the REST API hence we will need a client code to have it working. Create a new HTML file at the location: SpringbootandGooglecaptcha/src/main/resources/static and add the following code to it.

index.html

<html lang="en">
<head>
    <title>Springboot and Captcha</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" type="text/javascript"></script>
    <script src="https://www.google.com/recaptcha/api.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
    function validateAndGetCaptchaResponse() {
        const response = grecaptcha.getResponse();
        return response.length === 0 ? null : response;
    }
    $(document).ready(function () {
        $("#button").click(function () {
            $("#captcha-error").html("");
            let captchaResponse = validateAndGetCaptchaResponse();
            if (captchaResponse) {
                console.log("Captcha code accepted.")
                let name = $("#name").val();
                let requestObj = {
                    'name': name.length === 0 ? 'Dummy' : name,
                    'captchaResponse': captchaResponse
                };
                $.ajax({
                    type: "POST",
                    contentType: "application/json",
                    dataType: "json",
                    data: JSON.stringify(requestObj),
                    url: "http://localhost:9001/api/welcome",
                    success: function (data) {
                        alert(data.message);
                    }
                });
            } else {
                $("#captcha-error").html("You cannot leave the captcha code empty.");
            }
        });
    });
</script>
<div>
    <h3>Springboot and Google captcha example</h3>
    <!-- User input -->
    <label for="name">Enter name:</label>
    <input id="name" placeholder="say... Daniel" type="text"/>
    <button id="button" type="submit">Submit</button>
    <div> </div>
    <!-- Google captcha (I'm not robot checkbox) -->
    <!-- SITE_KEY - Represents the site_key generated by the Google reCaptcha service -->
    <div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY" id="recaptcha"></div>
    <span id="captcha-error" style="color:red"></span>
</div>
</body>
</html>

4. Run the Application

To execute the application, right-click on the SpringbootandGooglecaptchaApplication.java class, Run As -> Java Application.

Fig. 3: Run the Application

5. Project Demo

When the application is started, navigate to the following URL: http://localhost:9001/ and you’ll see the index page of the application with a reCAPTCHA “I’m not a robot” checkbox as shown in Fig. 4.

Fig. 4: Index page

The HTML code will call our backend endpoint (http://localhost:9001/api/welcome) with a name and captcha-response as the request body. Enter the user details, tick the reCAPTCHA checkbox, and press the button. On successful validation by the backend code, we’ll get a greetings alert.

Fig. 5: Greeting response

That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!

6. Summary

In this section, you learned,

You can download the sample application as an Eclipse project in the Downloads section.

7. Download the Project

This was an example of implementing Google reCAPTCHA in a Spring Boot application.

Download
You can download the full source code of this example here: Using Google Captcha with Spring Boot Application
Exit mobile version