JavaServer Pages CAPTCHA Ajax Validation Code Example

The JSP BotDetect built-in Ajax Captcha validation example shows how to properly perform Ajax CAPTCHA validation using built-in BotDetect CAPTCHA client-side functionality, which doesn't require any 3rd party Ajax frameworks.

First Time Here?

Check the BotDetect JSP Captcha Quickstart for key integration steps.

Ajax CAPTCHA validation improves the user experience by reducing CAPTCHA validation response time, giving users much faster feedback about the validation result.

Client-side validation is not secure by itself (it can be bypassed trivially), so the example also shows how the protected form action must always be secured by server-side CAPTCHA validation as well.

Downloaded Location

The JSP CAPTCHA Ajax validation Example is included in examples folder of the download package as bdc3-captcha-ajax-validation-example.war file. Deploying (unpacking) the file will create a standard JSP directory tree.

index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="botDetect" uri="botDetect"%>
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>BotDetect CAPTCHA Ajax Validation Example</title>
    <link rel="stylesheet" href="stylesheet.css" type="text/css"/>
  </head>
  <body>
    <form action="ajaxValidationAction" method="post">
      <h1>BotDetect CAPTCHA Ajax Validation Example</h1>
      <fieldset>
        <legend>CAPTCHA Validation</legend>
        <label for="captchaCodeTextBox" class="prompt">
            Retype the code from the picture:</label>
        <!-- Adding BotDetect Captcha to the page -->
        <botDetect:captcha id="ajaxValidatedCaptcha"/>
        <div class="validationDiv">
          <input id="captchaCodeTextBox" type="text" name="captchaCodeTextBox"
              onchange="return ajaxValidatedCaptcha.Validate();"/>
          <input type="submit" id="validateCaptchaButton" 
              name="validateCaptchaButton" value="Validate" />&nbsp;
          <%
          if(request.getAttribute("validationResult") != null){
            if(request.getAttribute("validationResult").equals("correct")){
              out.print("<span id=\"captchaCorrectLabel\" 
                  class=\"correct\">Correct! (server)</span>");
              out.print("<span id=\"captchaIncorrectLabel\" 
                  class=\"incorrect\"></span>");
            } else {
              out.print("<span id=\"captchaCorrectLabel\" 
                  class=\"correct\"></span>");
              out.print("<span id=\"captchaIncorrectLabel\" 
                  class=\"incorrect\">Incorrect! (server)</span>");
            }
          } else {
            out.print("<span id=\"captchaCorrectLabel\" 
                class=\"correct\"></span>");
            out.print("<span id=\"captchaIncorrectLabel\" 
                class=\"incorrect\"></span>");
          }
          %>
          <span id="captchaCorrectLabel" class="correct"></span>
          <span id="captchaIncorrectLabel" class="incorrect"></span>
        </div>
      </fieldset>
    </form>
    <script type="text/javascript">
      function OnCaptchaValidate() {
        // update display and disable the button
        document.getElementById('captchaCorrectLabel').style.display='none';
        document.getElementById('captchaIncorrectLabel').style.display='none';

        document.getElementById('validateCaptchaButton').disabled = true;
      }

      function OnCaptchaCorrect() {
        // update display
        document.getElementById('captchaCorrectLabel').innerHTML = 
            'Correct! (client)';
        document.getElementById('captchaCorrectLabel').style.display='inline';

        document.getElementById('captchaIncorrectLabel').style.display='none';

        // automatically proceed to server-side validation
        document.getElementById('validateCaptchaButton').disabled = false;
      }

      function OnCaptchaIncorrect() {
        // update display and enable the button for re-tries
        document.getElementById('captchaCorrectLabel').style.display = 'none';

        document.getElementById('captchaIncorrectLabel').innerHTML = 
            'Incorrect! (client)';
        document.getElementById('captchaIncorrectLabel').style.display = 
            'inline';

        document.getElementById('validateCaptchaButton').disabled = false;
      }

      function OnAjaxError() {
        // fall back to server-side validation
        document.getElementById('validateCaptchaButton').disabled = false;
      }
    </script>
    <script type="text/javascript">
      //<![CDATA[
      BotDetect.RegisterCustomHandler('PreAjaxValidate', OnCaptchaValidate);
      BotDetect.RegisterCustomHandler('AjaxValidationFailed', 
          OnCaptchaIncorrect);
      BotDetect.RegisterCustomHandler('AjaxValidationPassed', 
          OnCaptchaCorrect);
      BotDetect.RegisterCustomHandler('AjaxValidationError', 
          OnAjaxError);//]]>
    </script>
  </body>
</html>

The Captcha Ajax validation workflow is controlled by the four client-side methods defined on the page: OnCaptchaValidation, OnCaptchaCorrect, OnCaptchaIncorrect and OnAjaxError.

Handlers for the four Ajax-related client-side events will be automatically called by the Validate() function call at appropriate stages of the Ajax Captcha validation workflow.

Main concerns of these handlers are displaying the validation result, disabling multiple consecutive button clicks while Ajax validation is in progress, and handling Ajax errors and timeouts.

Details of the Ajax implementation are encapsulated in BotDetect source for easier use. They involve making an Ajax request at a special endpoint in the Captcha handler, and processing the returned JSON result. You do not need to concern yourself with such details, but can use the supplied Validate() function as is.

AjaxValidationAction.java

package botdetect.examples.jsp.ajax_validation.action;

import botdetect.web.Captcha;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AjaxValidationAction extends HttpServlet {
  @Override
  protected void doPost(HttpServletRequest request, 
      HttpServletResponse response)
      throws ServletException, IOException {

    Captcha captcha = Captcha.load(request, "ajaxValidatedCaptcha");
    
    // validate the Captcha to check we're not dealing with a bot
    boolean isHuman = captcha.validate(request, 
        request.getParameter("captchaCodeTextBox"));
    if (isHuman) {
      // Captcha validation passed, perform protected action
      request.setAttribute("validationResult", "correct");
    } else {
      // Captcha validation failed, show error message
      request.setAttribute("validationResult", "incorrect");
    }
    
    RequestDispatcher dispatcher = 
        getServletContext().getRequestDispatcher("/index.jsp");
    dispatcher.forward(request, response);
  }
}

Form action servlet is almost same as in the Captcha Tag Example because there are no changes in server-side validation procedure.

To run this example, botdetect.jar must be in the classpath.

Please Note

BotDetect Java Captcha Library v4.0.Beta3 is an in-progress port of BotDetect 4 Captcha, and we need you to guide our efforts towards a polished product. Please let us know if you encounter any bugs, implementation issues, or a usage scenario you would like to discuss.