Struts integration
Start with download
Introduction
This document is a tutorial that demonstrates how to integrate JCaptcha with a Struts based Web application using the Jcaptcha Struts module.
It Uses the struts-mailreader application bundled with the Struts distribution as the base web application to captcha-ize.
This tutorial is devided into 5 Steps.
- Step 1 : Prerequisites
- Step 2 : install and configure the jcaptcha struts plugin
- Step 3 : Indentify the to be captchai-zed page flow
- Step 4 : Short cut the identified actions with captcha action
- Step 5 : Modify the input page
Prerequisites
Install the struts-mailreader sample application in your favorite J2EE container.
Just deploy the war or the exploded war into your favorite application container deploy directory.
Install the jcaptcha struts plugin
- Copy the jcaptcha jar to the WEB-INF/lib dir of the struts-mailreader web-app : jcaptcha-all-$version.jar
- Copy the jcaptcha third parties jars to the WEB-INF/lib dir of the struts-mailreader web-app : ehcache-1.0.jar
- Add the following plugin declaration at the end of the struts config file
<plug-in className="com.octo.captcha.module.struts.CaptchaServicePlugin"/>
(there's many settable property available, but none are required, this is detailed in the module documentation).
Indentify the to be captchai-zed page flow
We want to captcha-ize the registration page flow in order to avoid robot registration spam...
This page flow concerns the following elements in struts-mailreader struts-config-registration.xml (using wildcard!!) file :
... <!-- ========== Form Bean Definitions =================================== --> <form-beans> <!-- Registration form bean --> <form-bean name="RegistrationForm" type="org.apache.struts.webapp.example.RegistrationForm"/> </form-beans> <!-- ========== Global Forward Definitions ============================== --> <global-forwards> <forward name="Registration" path="/Registration.jsp"/> </global-forwards> <!-- ========== Action Mapping Definitions ============================== --> <action-mappings> <!-- Matches all edit actions (in this case, only user regstration) --> <action path="/Edit*" type="org.apache.struts.webapp.example.Edit{1}Action" name="{1}Form" scope="request" validate="false"> <forward name="success" path="/{1}.jsp"/> </action> <!-- Matches all save actions (in this case, only user registration) --> <action path="/Save*" type="org.apache.struts.webapp.example.Save{1}Action" name="{1}Form" scope="request" input="{1}"/> </action-mappings> ...
Short cut
So what we have to do next is to short cut this action (SaveRegistration.do) to introduce a jcaptcha challenge verification action before calling the 'real' action.
In order to do it, we will
- create a new action called jcaptchaRegistration that will execute the 'real' action.
- replace the 'real' action class in order to execute the jcapthca validation routine
- Finaly add the render challenge action that will produce the image challenge to render.
The final configuration will look as follow :
<!-- Matches all edit actions (in this case, only user regstration) --> <action path="/Edit*" type="org.apache.struts.webapp.example.Edit{1}Action" name="{1}Form" scope="request" validate="false"> <forward name="success" path="/{1}.jsp"/> </action> <!-- Transform the wildCardAction to use the jcaptcha validation routine--> <action path="/SaveRegistration" type="com.octo.captcha.module.struts.VerifyCaptchaChallengeAction" name="RegistrationForm" scope="request" input="Registration" validate="false" > <forward name="success" path="/jcaptchaRegistration.do"/> </action> <!-- Add the real action --> <action path="/jcaptchaRegistration" type="org.apache.struts.webapp.example.SaveRegistrationAction" name="RegistrationForm" scope="request" input="Registration" > </action> <!-- add the render action--> <action path="/jcaptcha" type="com.octo.captcha.module.struts.image.RenderImageCaptchaAction" > </action>
Modify the input jsp
- adding the jcatcha taglib declaration
- adding a jcaptcha:message tag to add the failed message
- adding a jcaptcha:question tag to add the question
- adding an jcaptcha text input form
- adding an jcaptcha challenge
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="/tags/app" prefix="app" %> <%@ taglib uri="/tags/struts-bean" prefix="bean" %> <%@ taglib uri="/tags/struts-html" prefix="html" %> <%@ taglib uri="/tags/struts-logic" prefix="logic" %> <%-- Add the jcaptcha taglib--%> <%@ taglib uri="jcaptcha" prefix="jcaptcha"%> <logic:equal name="RegistrationForm" property="action" scope="request" value="Edit"> <app:checkLogon/> </logic:equal> <html:html> <head> <logic:equal name="RegistrationForm" property="action" scope="request" value="Create"> <title><bean:message key="registration.title.create"/></title> </logic:equal> <logic:equal name="RegistrationForm" property="action" scope="request" value="Edit"> <title><bean:message key="registration.title.edit"/></title> </logic:equal> <html:base/> </head> <body bgcolor="white"> <html:errors/> <%-- Add the message tag--%> <jcaptcha:message/> <html:form action="/SaveRegistration" focus="username" onsubmit="return validateRegistrationForm(this);"> <html:hidden property="action"/> <table border="0" width="100%"> <%-- Add the jcaptcha form part--%> <tr> <th align="right"> <jcaptcha:question/>: </th> <td align="left"> <%-- Add the image--%> <img src="jcaptcha.do"/> <br/> <%-- Add the input tag--%> <input type="text" name="jcaptcha_response" /> </td> </tr> <tr> <th align="right"> <bean:message key="prompt.username"/>: </th> <td align="left"> <logic:equal name="RegistrationForm" property="action" scope="request" value="Create"> <html:text property="username" size="16" maxlength="16"/> </logic:equal> <logic:equal name="RegistrationForm" property="action" scope="request" value="Edit"> <%-- <bean:write name="RegistrationForm" property="username" scope="request" filter="true"/> --%> <html:hidden property="username" write="true"/> </logic:equal> </td> </tr> ...
Remarks and best practices
As you may have noticed :
- We added a statistics page and links to demonstrate the manageable service features
- The captcha test is hackable by directly using the real action : Choose a wird action name in order to avoid direct call
- Chaining action as we just do in this tutorial is not recommended : Write your own action, use the sources of the VerifyCaptchaChallengeAction
- As you can see, the update profil page flow is also captch-ized : Be carrefull when you choose your page flow to captcha-ize, you may split a page flow to captch-ize just a part of it
- Use the user mailing list if you have more questions.