简体   繁体   中英

How to validate reCAPTCHA V2 Java (Servlet)

This is an Q&A style post, which I'll post both the question and an answer. The main reason for this 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.

How to do a server side validation of Google reCAPTCHA V2 or Invisible reCAPTCHA with Java ?

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.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.json.JSONObject;

Use the following method 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 synchronized boolean isCaptchaValid(String secretKey, String response) {
    try {
        String url = "https://www.google.com/recaptcha/api/siteverify",
                params = "secret=" + secretKey + "&response=" + response;

        HttpURLConnection http = (HttpURLConnection) new URL(url).openConnection();
        http.setDoOutput(true);
        http.setRequestMethod("POST");
        http.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded; charset=UTF-8");
        OutputStream out = http.getOutputStream();
        out.write(params.getBytes("UTF-8"));
        out.flush();
        out.close();

        InputStream res = http.getInputStream();
        BufferedReader rd = new BufferedReader(new InputStreamReader(res, "UTF-8"));

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

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

Call the above method as shown below,

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

Hope this helps. Cheers!


EDIT: Using the POST method to verify information as recommended byGoogle , is way more safer, however if you need the GET method version please refer the edit history .

Don't encode the params variable . You will always get the below response by doing so.

{"error-codes":["missing-input-response","missing-input-secret"],"success":false}

Just to provide another variant:

import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import javax.ws.rs.client.*;
import javax.ws.rs.core.*;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.*;

@Component
public class ReCaptcha {

    private final WebTarget webTarget;

    public ReCaptcha() {
        webTarget = ClientBuilder.newClient()
                .target("https://www.google.com/recaptcha/api/siteverify")
                .queryParam("secret", "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe");
    }

    public boolean isValid(@NotNull String token) throws IOException {
        Response response = this.webTarget.queryParam("response", token)
                .request(MediaType.APPLICATION_JSON)
                .accept("application/ld+json")
                .get();

        if (response.getStatus() != 200)
            return false;

        String stringResponse = response.readEntity(String.class);
        JsonNode jsonNode = new ObjectMapper().readTree(stringResponse);
        return jsonNode.get("success").asBoolean();
    }
}

In addition you could validate the returned hostname and action. Also you might want to log returned error codes.

You will have to replace the used API key with your own (this is a test API key and should always return that the token is valid: https://developers.google.com/recaptcha/docs/faq ) It also might be a good idea to put the API key and API url into a extra property file.

You can inject this class everywhere you like.

I use it with special exceptions instead of returning true or false.

For use with webmail scripts and comment boxes:

if(isCaptchaValid("secret", request.getParameter("g-recaptcha-response"))){
  request.setAttribute("Captcha", "true");
try {
  Mailserver.sendEmail(host, port, user, pass, recipient, subject, name, email, content);
  resultMessage = "The e-mail is sent successfully!";
  getServletContext().getRequestDispatcher("/captchacorrect.jsp").forward(request, response);
} catch (Exception ex) {
  ex.printStackTrace();
  resultMessage = "An error occured: " + ex.getMessage();
} finally {
  request.setAttribute("Message", resultMessage);
}
} else {
    getServletContext().getRequestDispatcher("/captchawrong.jsp").forward(request, response);
  } }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM