2
\$\begingroup\$

The main reason for this post is that I spent quite a lot of time searching the easiest way to validate recaptcha V2. So I'm going to share my knowledge to avoid further time wastage of developers.

I'm using org.json library for this. Get the .jar file from here or read the docs. Add the .jar. file to your project and import the following classes.

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import org.json.JSONObject;

Use the following method to for validation:

/**
 * Validates Google reCAPTCHA V2 or Invisible reCAPTCHA.
 * @param secretKey Secret key (key given for communication between your site and Google)
 * @param response reCAPTCHA response from client side. (g-recaptcha-response)
 * @return true if validation successful, false otherwise.
 */
public static boolean isCaptchaValid(String secretKey, String response) {
    try {
        String url = "https://www.google.com/recaptcha/api/siteverify?"
                + "secret=" + secretKey
                + "&response=" + response;
        InputStream res = new URL(url).openStream();
        BufferedReader rd = new BufferedReader(new InputStreamReader(res, Charset.forName("UTF-8")));

        StringBuilder sb = new StringBuilder();
        int cp;
        while ((cp = rd.read()) != -1) {
            sb.append((char) cp);
        }
        String jsonText = sb.toString();
        res.close();

        JSONObject json = new JSONObject(jsonText);
        return json.getBoolean("success");
    } catch (Exception e) {
        return false;
    }
}

Call the above method as shown:

if(isCaptchaValid("enter_your_key_here", request.getParameter("g-recaptcha-response"))){
    //valid
}
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

One small criticism of you're code that I'll offer is that the loop in the middle which reads a stream could be usefully factored out and put in a general utility. Reading a stream is a common problem and could be made more general.

In fact I have a small routine to do that sitting here on my hard drive. Here's my version:

public class IoUtils
{

   private IoUtils() {}

   public static CharSequence readFully( Reader reader )
           throws IOException
   {
      char[] buffer = new char[ 1024 ];
      StringBuilder stringBuilder = new StringBuilder();
      for( int length; ( length = reader.read( buffer ) ) != -1; )
         stringBuilder.append( buffer, 0, length );
      return stringBuilder;
   }

   public static ByteArrayOutputStream readFully( InputStream ins )
           throws IOException
   {
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      byte[] bytes = new byte[ 1024 ];
      for( int length; ( length = ins.read( bytes ) ) != -1; )
         bos.write( bytes, 0, length );
      return bos;
   }
}

Use it something like this:

    InputStream res = new URL(url).openStream();
    BufferedReader rd = new BufferedReader(new InputStreamReader(res, Charset.forName("UTF-8")));

    CharSequence cs = IoUtils.readFully( rd );

    JSONObject json = new JSONObject( cs.toString() );

Reading a stream as UTF-8 is so common you might even want to make a separate method just for that. Then you could do

JSONObject json = new JSONObject( IoUtils.readFullyUtf8( 
         new URL(url).openStream() ).toString() );

Some might find a single line of code more clear to read.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.