Java – reCAPTCHA v2

En este ejemplo te mostraremos como integrar el servicio de reCAPTCHAv2 de Google a una página de acceso simulando una aplicación que solicita usuario y contraseña.

El registro en Google

El primer paso es registrar el dominio de tu aplicación en la página de Google:

https://www.google.com/recaptcha/admin#list


El administrador luce más o menos de la siguiente forma:

El servicio de reCAPTCHAv2 de Google te permite agregar uno o varios dominios.  Después de agregar el tuyo, Google te proporcionará una clave de sitio y una clave secreta como se muestra a continuación:

Estos datos serán usados más adelante.

Importante: para esta prueba modificamos la configuración en el servicio de Google para que permita el uso de localhost como dominio de prueba.

Este ejemplo lo hemos creado como proyecto Web en Maven con la ayuda de NetBeans 8.2 y agregamos las siguientes dependencias:

        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.json</artifactId>
            <version>1.1.2</version>
        </dependency>

Crearemos los siguientes archivos en nuestro proyecto:

  •  index.jsp – Es el JSP de inicio y donde colocaremos las entradas de login, password y confirmación de Captcha.
  • entradaExitosa.jsp – Si el usuario, la contraseña y la prueba de captcha son correctas se desplegará esta página de bienvenida.
  • LoginServlet.java – Servlet con el control y la lógica de acceso.
  • VerificarRecaptcha.java – Se encarga de verificar el resultado de la prueba captcha con el servicio de Google.

El primer JSP – index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Pagina de inicio</title>
      <script src="https://www.google.com/recaptcha/api.js"></script>
   </head>
   <body>
      <form action="LoginServlet" method="post">
         <table>
            <tbody>
               <tr>
                  <td>
                     usuario:
                  </td>
                  <td>
                     <input type="text" name="usuario">
                  </td>
               </tr>
               <tr>
                  <td>
                     password:
                  </td>
                  <td>
                     <input type="password" name="password">
                  </td>
               </tr>
               <tr>
                  <td></td>
                  <td>
                     <div class="g-recaptcha" data-sitekey="6LchMm4UAAAAAChlkD00000000000tMEqNV_h"></div>
                  </td>
               </tr>
               <tr>
                  <td></td>
                  <td>
                     <input type="submit" value="Login">
                  </td>
               </tr>
            </tbody>
         </table>
      </form>
   </body>
</html>

Es importante que en este archivo de inicio reemplaces la llave de sitio que obtuviste en tu registro.

<div class="g-recaptcha" data-sitekey="6LchMm4UAAAAAChlkD00000000000tMEqNV_h"></div>

Nuestro segundo JSP – entradaExitosa.jsp

Solo muestra un texto de bienvenida y un enlace a la página de inicio.

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta charset="UTF-8">
        <title>Pagina principal</title>
    </head>
    <body>
        <h3>Bienvenido</h3>
        <a href="index.jsp">Página de inicio</a>
    </body>
</html>

El servlet que controla el acceso – LoginServlet.java

Ahora es necesario crear el servlet, para lo cual usamos el Wizzard de NetBeans, pero finalmente modificamos el código de la siguiente forma:

package com.decodigo.servlet;

import com.decodigo.utils.VerificarRecaptcha;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author decodigo
 */
@WebServlet(name = "LoginServlet", urlPatterns = {"/LoginServlet"}, initParams = {
		@WebInitParam(name = "usuario", value = "decodigo"),
		@WebInitParam(name = "password", value = "123") })
public class LoginServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String usuario = request.getParameter("usuario");
        String password = request.getParameter("password");
        
        String gRecaptchaResponse = request.getParameter("g-recaptcha-response");
        System.out.println(gRecaptchaResponse);
        
        boolean verificado = VerificarRecaptcha.verificar(gRecaptchaResponse);

        String usuarioRegistrado = getServletConfig().getInitParameter("usuario");
        String passwordRegistrado = getServletConfig().getInitParameter("password");

        System.out.println("usuario: " + usuario);
        System.out.println("password: " + password);
        System.out.println("captcha: " + verificado);

        if (usuarioRegistrado.equals(usuario) && passwordRegistrado.equals(password) && verificado) {
            response.sendRedirect("entradaExitosa.jsp");
        } else {
            RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
            PrintWriter out = response.getWriter();
            if (verificado) {
                out.println("El usuario o password son incorrectos.");
            } else {
                out.println("Captcha incorrecto.");
            }
            rd.include(request, response);
        }
    }
}

Este Servlet hace algunas cosas interesantes. Verifica que el usuario y la contraseña sean correctas. Pero lo más importante es el uso de la clase VerificarRecaptcha para confirmar mediante el servicio de Google que el resultado de la prueba captcha haya sido exitosa.

La clase – VerificarRecaptcha.java

package com.decodigo.utils;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URL;

import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.net.ssl.HttpsURLConnection;

/**
 *
 * @author decodigo
 */
public class VerificarRecaptcha {

    public static final String url = "https://www.google.com/recaptcha/api/siteverify";
    public static final String secreto = "6LchMm4UAA00000000000b0ewwbuU2o-0";
    private final static String USER_AGENT = "Mozilla/5.0";

    public static boolean verificar(String gRecaptchaResponse) throws IOException {
        if (gRecaptchaResponse == null || "".equals(gRecaptchaResponse)) {
            return false;
        }

        try {
            URL obj = new URL(url);
            HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();

            con.setRequestMethod("POST");
            con.setRequestProperty("User-Agent", USER_AGENT);
            con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");

            String postParams = "secret=" + secreto + "&response=" + gRecaptchaResponse;

            con.setDoOutput(true);
            DataOutputStream wr = new DataOutputStream(con.getOutputStream());
            wr.writeBytes(postParams);
            wr.flush();
            wr.close();

            int responseCode = con.getResponseCode();
            System.out.println("Enviando 'POST' peticion a URL : " + url);
            System.out.println("Parametros post : " + postParams);
            System.out.println("Codigo de respuesta : " + responseCode);

            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String inputLine;
            StringBuffer respuesta = new StringBuffer();

            while ((inputLine = in.readLine()) != null) {
                respuesta.append(inputLine);
            }
            in.close();

            System.out.println(respuesta.toString());

            JsonReader jsonReader = Json.createReader(new StringReader(respuesta.toString()));
            JsonObject jsonObject = jsonReader.readObject();
            jsonReader.close();

            return jsonObject.getBoolean("success");
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

En VerificarRecaptcha, del mismo modo que en el JSP de inicio, debes reemplazar la clave secreta que se generó durante el registro.  En esta clase se hace la consulta con el servicio de Google.  En la página de inicio se genera una respuesta, producto de la prueba del captcha.

String gRecaptchaResponse = request.getParameter(«g-recaptcha-response»);

Esta respuesta es enviada nuevamente al servicio de Google «https://www.google.com/recaptcha/api/siteverify«, el servicio evalúa si la prueba de captcha se ha realizado exitosamente y si es así devuelve una respuesta de confirmación.

Si ejecutas la aplicación Web desplegándola en Tomcat tendrás el resultado siguiente:

Al dar click en el checkbox «No soy un robot» la prueba comenzará y esta será tan difícil o fácil, dependiendo de como configures su dificultad en el administrador del servicio de Google.

Si el visitante pasa la prueba de reCAPTCHAv2 el componente mostrará la confirmación de éxito.

Al dar click en «Login» el servlet se encarga de procesar la petición y te mostrará una sencilla pantalla de bienvenida.

Si el usuario evade la prueba de reCAPTCHAv2, entonces se mostrará un mensaje de error.

Como puedes ver es muy sencillo implementar este servicio.  La clase VerificarRecaptcha puede parecer complicada, pero no tendrás que modificarla demasiado. No olvides que Google actualiza y mejora frecuentemente sus servicios. Es posible que la apariencia del servicio de administración de dominios no sea la misma en un futuro.