BotDetect CAPTCHA Options: Request Dynamic Settings Code Example
The Java Captcha options: Request dynamic settings code example shows how to dynamically adjust Captcha configuration, potentially on each Http request made by the client.
First Time Here?
Check the BotDetect Developer Crash Course for key integration steps.
Any Java code setting Captcha properties in the CaptchaFilter.java
file will be executed not only for each protected form GET or POST request (like Captcha configuration code placed in form source would be), but also for each GET request loading a Captcha image or sound, or making an Ajax Captcha validation call.
If configured values are dynamic (e.g. CaptchaRandomization
helper or other function calls in CaptchaFilter.java
code), they will be re-calculated for each Captcha challenge generated. For example, Captcha ImageStyle
randomized in CaptchaFilter.java
code will change on each Captcha reload button click.
This means your code can reliably keep track of visitor interaction with the Captcha challenge and dynamically adjust its settings. Also, while CaptchaFilter.java
settings apply to all Captcha instances by default, you can also selectively apply them based on CaptchaId.
To show an example of the possible dynamic Captcha configuration adjustments, this code example increases the difficulty of the Captcha test if the visitor associated with the current Java Session fails a certain number of Captcha validation attempts, and also sets the Captcha locale to Chinese for requests from a certain IP range.
Download the BotDetect Java CAPTCHA Library and run this exampleWithin this page, the root folder of the extracted archive is referred as the <BDC-DIR>
.
This example is in the <BDC-DIR>/examples/t_api-captcha~conf_via-dynamic_config/
folder; and contains the following files:
- index.jsp
- WEB-INF/web.xml
- WEB-INF/src/com/captcha/botdetect/examples/dynamic_captcha/Counter.java
- WEB-INF/src/com/captcha/botdetect/examples/dynamic_captcha/CaptchaFilter.java
Running Example
This example's war file (in BotDetect download package) already embeds all dependencies.
In case you are making this example from scratch in your IDE, you need to ensure botdetect.jar
and botdetect-servlet.jar
are in the classpath.
index.jsp
<%@page import="com.captcha.botdetect.CodeStyle"%> <%@page import="com.captcha.botdetect.examples.dynamic_captcha.Counter"%> <%@page import="com.captcha.botdetect.web.servlet.Captcha"%> <%@page trimDirectiveWhitespaces="true"%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>BotDetect Java CAPTCHA Options: Request Dynamic Settings Code Example</title> <link type="text/css" rel="stylesheet" href="stylesheet.css" /> </head> <body> <form method="post" action="" class="column" id="form1"> <h1>BotDetect Java CAPTCHA Options: <br /> Request Dynamic Settings Code Example</h1> <fieldset> <legend>Java CAPTCHA validation</legend> <label for="captchaCode">Retype the characters from the picture:</label> <% // Adding BotDetect Captcha to the page Captcha captcha = Captcha.load(request, "dynamicCaptcha"); captcha.setUserInputID("captchaCode"); String captchaHtml = captcha.getHtml(); out.write(captchaHtml); %> <div class="validationDiv"> <input name="captchaCode" type="text" id="captchaCode" /> <input type="submit" name="SubmitButton" id="SubmitButton" value="Submit Form" /> <% Counter counter = new Counter(request.getSession()); if ("POST".equalsIgnoreCase(request.getMethod())) { // validate the Captcha to check we're not dealing with a bot boolean isHuman = captcha.validate(request.getParameter("captchaCode")); if (!isHuman) { // Captcha validation failed, show error message out.print("<span class=\"incorrect\">Incorrect code</span>"); counter.incrementFailedValidationsCount(); } else { // Captcha validation passed, perform protected action out.print("<span class=\"correct\">Correct code</span>"); counter.resetFailedValidationsCount(); } } %> </div> </fieldset> <div id="output"> <% Integer count = counter.getFailedValidationsCount(); %> <p>Failed Captcha validations: <%= count %></p> <% if (count < 3) { out.print("<p>Dynamic Captcha difficulty: Easy</p>"); } else if (count < 10) { out.print("<p>Dynamic Captcha difficulty: Moderate</p>"); } else { out.print("<p>Dynamic Captcha difficulty: Hard</p>"); } %> </div> </form> </body> </html>
In the form source, we follow the standard procedure for adding Captcha protection to a JSP form.
On POST request, if Captcha validation fails, the increment of failed validation is executed by calling incrementFailedValidationsCount()
method of counter
object. Otherwise, it will be reset by calling the resetFailedValidationsCount()
method of counter
object.
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <session-config> <session-timeout> 30 </session-timeout> </session-config> <servlet> <servlet-name>BotDetect Captcha</servlet-name> <servlet-class>com.captcha.botdetect.web.servlet.CaptchaServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>BotDetect Captcha</servlet-name> <url-pattern>/botdetectcaptcha</url-pattern> </servlet-mapping> <filter> <filter-name>captchaFilter</filter-name> <filter-class>com.captcha.botdetect.examples.dynamic_captcha.CaptchaFilter</filter-class> </filter> <filter-mapping> <filter-name>captchaFilter</filter-name> <servlet-name>BotDetect Captcha</servlet-name> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
In WEB-INF/web.xml
file we declare custom filter and map it to BotDetect Captcha
servlet in order to dynamically adjust Captcha configuration for every Captcha generation request.
Counter.php
package com.captcha.botdetect.examples.dynamic_captcha; import javax.servlet.http.HttpSession; /** * Helper class for counting Captcha validation failures at form submission */ public class Counter { private HttpSession session; private static final String FAILED_VALIDATIONS_COUNT_KEY = "failedValidationsCount"; public Counter(HttpSession session) { this.session = session; } public int getFailedValidationsCount() { Integer count = (Integer) session.getAttribute(FAILED_VALIDATIONS_COUNT_KEY); if (count == null) { count = 0; } return count.intValue(); } public void incrementFailedValidationsCount() { int count = getFailedValidationsCount(); count++; session.setAttribute(FAILED_VALIDATIONS_COUNT_KEY, count); } public void resetFailedValidationsCount() { session.removeAttribute(FAILED_VALIDATIONS_COUNT_KEY); } }
The helper class for counting Captcha validation failures at form submission.
CaptchaFilter.java
package com.captcha.botdetect.examples.dynamic_captcha; import com.captcha.botdetect.CaptchaRandomization; import com.captcha.botdetect.CodeStyle; import com.captcha.botdetect.web.CaptchaHttpCommand; import com.captcha.botdetect.web.servlet.Captcha; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; public class CaptchaFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { CaptchaHttpCommand command = CaptchaHttpCommand.getCaptchaCommand(request.getParameter("get")); if ((command == CaptchaHttpCommand.GET_IMAGE) || (command == CaptchaHttpCommand.GET_SOUND) || (command == CaptchaHttpCommand.GET_VALIDATION_RESULT)) { String captchaId = request.getParameter("c"); Captcha captcha = Captcha.load(request, captchaId); // Dynamic Captcha settings depending on failed validation attempts: increase Captcha // difficulty according to number of previously failed validations Counter counter = new Counter(((HttpServletRequest) request).getSession()); Integer count = counter.getFailedValidationsCount(); if (count < 3) { captcha.setCodeLength(CaptchaRandomization.getRandomCodeLength(3, 4)); captcha.setCodeStyle(CodeStyle.NUMERIC); captcha.setCodeTimeout(600); // 10 minutes } else if (count < 10) { captcha.setCodeLength(CaptchaRandomization.getRandomCodeLength(4, 6)); captcha.setCodeStyle(CodeStyle.ALPHA); captcha.setCodeTimeout(180); // 3 minutes } else { captcha.setCodeLength(CaptchaRandomization.getRandomCodeLength(6, 9)); captcha.setCodeStyle(CodeStyle.ALPHANUMERIC); captcha.setCodeTimeout(60); // 1 minutes } // Set Captcha locale to Chinese for requests from a certain IP range String testIPRange = "223.254."; if (request.getRemoteAddr().startsWith(testIPRange)) { captcha.setCodeStyle(CodeStyle.ALPHA); captcha.setLocale("cmn"); } // Save captcha settings captcha.save(captcha); } chain.doFilter(request, response); } @Override public void destroy() { } @Override public void init(FilterConfig filterConfig) { } }
The dynamic Captcha settings will have various values according to number of previously failed validations. It also sets Captcha locale to Chinese for requests from a certain IP range (i.e. '223.254.' in code above) .
Please Note
BotDetect Java Captcha Library v4.0.Beta3.7 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.
Current BotDetect Versions
-
BotDetect ASP.NET CAPTCHA
2019-07-22v4.4.2 -
BotDetect Java CAPTCHA
2019-07-22v4.0.Beta3.7 -
BotDetect PHP CAPTCHA
2019-07-22v4.2.5