JCAPTCHA with AppFuse via Struts

来源:互联网 发布:凡科如何使用现有域名 编辑:程序博客网 时间:2024/04/28 22:06

Here's my way of integrating JCAPTCHA with AppFuse to utilize captcha images within the Acegi security framework. This method is my own extension of an excellent article by Petr Matul'k that was focused solely on JCAPTCHA-SpringFramework integration. My method extends this for use with the kickstart application AppFuse by Matt Raible, leveraging Struts and many of Matt's constructs from AppFuse.

There are two ways that JCAPTCHA can be used with this implementation: 1) Acegi-Security method, and 2) Custom Captcha method. Both implementation methods can be used simultaneously as well, as they work together and leverage 95% of the same code. The example below shows how to captcha-secure the AppFuse signup.html page.

The Acegi-Security method allows you to use the Acegi captcha provider framework to provide security to your web application. Generally this means that there will be a resource, like a file url, that you want to secure with a captcha. You add the url to the Acegi configuration as a protected resource and when a user browses to that url, they get a captcha challenge. If they pass the captcha challenge, they get access to the resource, and henceforth are considered a "human" within the Acegi framework. When the user logs out, their session is invalidated, and they are no longer considered a human by the webapp. The next time they try to view the protected url resource, they are challenged with a captcha again.

The Custom Captcha method allows you to use a captcha image within any form, as part of that form. Therefore your user will most likely be entering other information (like user registration info) on the same form and the captcha will appear at the bottom of the form. The test for humanity occurs in the controller level of the AppFuse (Struts) MVC infrastructure, in a custom Struts Action. The humanity check is always performed within the Struts Action, regardless of the state of "isHuman" within the Acegi security framework.

If you wish to use my methods below, here are the prerequisites: 1) AppFuse v1.9, 2) Acegi-Security v1.0.0-FINAL, 3) JCAPTCHA v1.0-RC3. I also assume that you've already generated a webapp using AppFuse and you've already started customizing the webapp for your business needs. When I refer to "myapp" below, I'm talking about the generated application, and java packages, that you created from AppFuse.

  1. AppFuse needs to be patched to Acegi-Security v1.0.0-FINAL to fix a few bugs. Do this by placing the new Acegi jar file in: myapp/lib/spring-1.2.7/acegi-security-1.0.0.jar and deleting the old acegi-security-1.0.0-RC2.jar file.

    Add JCAPTCHA to your webapp by creating the myapp/lib/jcaptcha-1.0-RC3/ directory and placing the jcaptcha-all-1.0-RC3.jar inside it. Then edit the myapp/lib/lib.properties file and add:

    Then you need to tell ant to use the jcaptcha jar file for compiling, so edit the myapp/properties.xml and add: <pathelement location="${jcaptcha.jar}"/> as a child of to the <path id="service.compile.classpath"> and <path id="web.compile.classpath"> elements. Now tell ant to add JCAPTCHA to the webapp's war file by editing the build.xml file and adding <lib file="${jcaptcha.jar}"/> to the <war> tag of the <target name="package-web" ...> target.
  2. This would be a good point to do a clean build of yor war file using ant. The application should compile and run just fine. The upgraded Acegi-Security jar and added JCAPTCHA jar should now live in the war file's WEB-INF/lib directory. If the compile, war file, and application are still working, then proceed to the next step.

  3. The next step is to get JCAPTCHA to generate images that are accessible via a web browser. This will be done with servlet that generates jpeg captcha images using JCAPTCHA and the SpringFramework. Start by defining the servlet in the myapp/web/WEB-INF/web.xml file as:

  4. Now define the JCAPTCHA configuration in the SpringFramework by adding a bean to the file: myapp/WEB-INF/applicationContext-security.xml. You will need to read an excellent tutorial detailing how to configure JCAPTCHA with SpringFramework. Specifically, the imageEngine defined in the bean below needs to be flushed out to configure image generation: it won't work as shown and the details are beyond the scope of this post.

  5. Here's the servlet code that renders the JPEG captcha images and registers the session ID with the JCAPTCHA infrastructure. Create the file as myapp/src/web/com/myapp/webapp/servlet/ImageCaptchaServlet.java. After creating this servlet and configuring JCAPTCHA via the SpringFramework, you should be able to compile the webapp, create the war, deploy to your container, and see captcha images via a url like: http://127.0.0.1:8080/myapp/captcha.jpg. If the servlet is not generating images, recheck the configuration before proceeding.

  6. The servlet should now be generating captcha images just fine. This next section details the Acegi-Security method (versus the Custom Captcha method) to secure a web resource, like a url, using that captcha image. First, we define a proxy according to the CaptchaServiceProxy defined by Acegi. This allows Acegi to access JCAPTCHA.

  7. Struts uses Forms and Actions to handle user interaction. A CaptchaForm needs to be defined to handle manipulation of the "next url" that the user is forwarded to when they successfully pass the captcha. Create the following file as myapp/src/web/com/myapp/webapp/form/CaptchaForm.java. Note that there are several meta-tags in this file that are used to generate the appropriate struts-config.xml entries.

  8. A struts Action needs to be defined to handle checking of the humanity state inside the Acegi framework. The action also saves the "next url" back to the form and other parameters back to the form. This action is unaware of the JCAPTCHA api, it only uses the Acegi and Struts classes. Create it as: myapp/src/web/com/myapp/webapp/action/CaptchaAction.java. Note that there are several meta-tags in this file that are used to generate the appropriate struts-config.xml entries.

  9. You will need a JSP page to render the form captcha image. Create the file below as myapp/web/pages/captcha.jsp

  10. Append the appropriate text to myapp/web/WEB-INF/classes/ApplicationResources.properties as needed below. This is used to render messages within the JSP.

  11. Edit the myapp/web/WEB-INF/applicationContext-security.xml file to integrate Acegi with your JCAPTCHA proxy created above. In the <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> entry, change:

    to:
    Replace:
    with:
    In this section we need to define the resource that is being protected:

    replace the contents of <value/> with:
    Replace the entire:
    with this:
    Finally, insert the new bean definitions below. Note that the "captchaResponse" parameter must match the one in the JSP file, and the "imageCaptchaService" bean id was defined earlier when we setup the captcha.jpg url.
  12. Next, add a Acegi servlet filter to the web.xml file so that the new channelFilter captures jsp and html page requests. Edit the myapp/web/WEB-INF/web.xml file by adding a new filter immediately after this securityFilter:
    <filter>
      <filter-name>securityFilter</filter-name>
     <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
      <init-param>
        <param-name>targetClass</param-name>
        <param-value>org.acegisecurity.util.FilterChainProxy</param-value>
      </init-param>
    </filter>

  13. At this point, your webapp should be ready to use Acegi to protect the /signup.html url via captcha. Use ant to clean and rebuild the war file, then redeploy the war to the servlet container. The application's login page should still be the default page. When you choose the "Signup" link, you should see the captcha challenge JSP page render. If you click on the captcha image, you should get a new image (just incase the captcha us too hard). If you fill in the captcha response box corretly and submit the form, you should be presented with the signup.html page. You shouldn't be challenged via captcha again, until your session is invalidated.

  14. The Custom Captcha method of adding captcha to an AppFuse project is to use add a challenge to an existing form. The same captcha.jsp servlet is used to generate images. The first step is to modify the myapp/web/pages/signup.jsp file to add the captcha:

  15. Now modify the AppFuse-generated file myapp/src/web/com/myapp/webapp/action/SignupAction.java to provide a humanity check by calling the imageCaptchaService bean defined in Spring. Add the following code block after the User user = (User) convert(form); line.

  16. Lastly, add the captcha element to the user object. Edit the file: myapp/src/dao/com/myapp/model/User.java, by adding the following code block.

  17. Now recompile, rebuild and redeploy the war file, and you should have a captcha challenge within both on the first request to the singup.html page, and ON the signup.html page. You would probably frustrate users if you used both, but the proof of concept now exists and you can use either method as you see fit within your webapp.

 
原创粉丝点击