Thursday, October 28, 2010

Roll your own Ajax-Based Captcha in Grails

Recently, I was asked to come up with a better solution to our captcha needs. We have been using ReCaptcha, which is great but difficult to read at times, and has caused frustrated customers and lost sales. I found a great solution at http://www.jkdesign.org/captcha which displays a number of graphics and let's the user choose the right one to prove they are human. Here is a screenshot of my implementation:
To make this work within Grails, I had to make several tweaks. The following files are required:

Create a new controller called Captcha. This can really be named anything, but if you do rename it, it will have to be updated in the jquery.simpleCaptcha-0.2.js file or passed in as an option via the javascript.

What this controller does is return a JSON object with the data needed to generate the captcha. The JSON appears like so:

Now we just need to implement this in our GSP file and controller. Suppose we have a page like shown above with a pickup code and the last 4 digits of the persons phone number. With adding our captcha div and required javascript, our GSP would look like this:

Finally, we need to perform the validation on the controller side. The modified authentication action would look like the following:

So there ya go. It's actually pretty easy and customers seem to like choosing an image much more than typing a word that is difficult to read.

3 comments:

  1. Hi.

    really great idea! Definetly worth remembering!

    ReplyDelete
  2. Hello there, my name is Jordan, author of simpleCaptcha. If you would like me to include your Grails implementation in the release, please send over all files to jquery aht jordankasper d com. Of course, you don't have to, but I'm sure some others will appreciate it.

    Glad to see it worked out for you!

    ReplyDelete
  3. I actually went a step further and used the generated hash as a "key" for the image in a custom rendering action in my controller, so that an association can't be made between an image URL and the name listed for selection.

    The action translates the hash into the "actual" URL of the CAPTCHA image and renders the image. With this, instead of passing the URL of the image in to simpleCaptcha, I can pass my custom URL with the hash as a parameter.

    ReplyDelete