Introduction
This plugin is designed to make using the ReCaptcha service within Grails easy. In order to use this plugin, you must have a ReCaptcha account, available from
http://recaptcha.net.
Installation
This plugin is easily installed from the Grails plugin repository.
Issue this command to install:
grails install-plugin recaptcha .
Usage
The plugin is simple to use. In order to use it, there are four basic steps:
Edit the Configuration
The plugin creates a file called
RecaptchaConfig.groovy in
grails-app/conf that has the following content:
recaptcha {
// These keys are generated by the ReCaptcha service
publicKey = ""
privateKey = "" // Include the noscript tags in the generated captcha
includeNoScript = true
}environments {
development {
recaptcha {
// Set to false to disable the display of captcha
enabled = false // Communicate using HTTPS
useSecureAPI = false
}
}
production {
recaptcha {
// Set to false to disable the display of captcha
enabled = true // Communicate using HTTPS
useSecureAPI = true
}
}
}
The values are pretty self-explanatory, and match with values used by the ReCaptcha service. You must enter your public and private ReCaptcha keys, or errors will be thrown when trying to display a captcha. Note that you can override values within the
environments closure.
Use the Tag Library
The plugin includes three tags:
<recaptcha:ifEnabled> ,
<recaptcha:recaptcha> , and
<recaptcha:ifFailed> .
- The
<recaptcha:ifEnabled> tag is a simple utility tag that will render the contents of the tag if the captcha is enabled in RecaptchaConfig.groovy .
- The
<recaptcha:recaptcha> tag is responsible for generating the correct HTML output to display the captcha. It supports four attributes: "theme", "lang", "tabindex", and "custom_theme_widget". These attributes map directly to the values that can be set according to the ReCaptcha API. See the ReCaptcha Client Guide for more details.
- The
<recaptcha:ifFailed> tag will render its contents if the previous validation failed. Some ReCaptcha themes, like "clean", do not display error messages and require the developer to show an error message. Use this tag if you're using one of these themes.
Verify the Captcha
In your controller, call
recaptchaService.verifyAnswer(session, request.getRemoteAddr(), params) to verify the answer provided by the user. This method will return true or false, but will set the
error_message property on the captcha behind the scenes so that the error message will be properly displayed when the ReCaptcha is redisplayed. Also note that
verifyAnswer will return
true if the plugin has been disabled in the configuration - this means you won't have to change your controller.
Clean up After Yourself
Once the captcha has been verified, call
recaptchaService.cleanUp(session) . This is not strictly needed, but it will clean the errors from the session.
Examples
Here's a simple example pulled from an account creation application.
Tag Usage
In
create.gsp , we add the code to show the captcha:
<recaptcha:ifEnabled>
<recaptcha:recaptcha theme="blackglass"/>
</recaptcha:ifEnabled>
In this example, we're using ReCaptcha's "blackglass" theme. Leaving out the "theme" attribute will default the captcha to the "red" theme.
If you are using a theme that does not supply error messages, your code might look like this:
<recaptcha:ifEnabled>
<recaptcha:recaptcha theme="clean"/>
<recaptcha:ifFailed>CAPTCHA Failed</recaptcha:ifFailed>
</recaptcha:ifEnabled>Verify User Input
Here's an abbreviated controller class that verifies the captcha value when a new user is saved:
import com.megatome.grails.RecaptchaService
class UserController {
RecaptchaService recaptchaService def save = {
def user = new User(params)
...other validation…
def recaptchaOK = true
if (!recaptchaService.verifyAnswer(session, request.getRemoteAddr(), params)) {
recaptchaOK = false
}
if(!user.hasErrors() && recaptchaOK && user.save()) {
recaptchaService.cleanUp(session)
...other account creation acivities…
render(view:'showConfirmation',model:[user:user])
}
else {
render(view:'create',model:[user:user])
}
}
}Testing
With version 0.4.5, the plugin should be easier to integrate into test scenarios. You can look at the test cases in the plugin itself, or you can implement something similar to:
private void buildAndCheckAnswer(def postText, def expectedValid, def expectedErrorMessage) {
def mocker = new MockFor(Post.class)
mocker.demand.getQueryString(4..4) { new QueryString() }
mocker.demand.getText { postText }
mocker.use {
def response = recaptchaService.checkAnswer("123.123.123.123", "abcdefghijklmnop", "response") assertTrue response.valid == expectedValid
assertEquals expectedErrorMessage, response.errorMessage
}
}The
postText parameter represents the response from the ReCaptcha server. Here are examples of simulating success and failure results:
public void testCheckAnswerSuccess() {
// ReCaptcha server will return true to indicate success
buildAndCheckAnswer("true", true, null)
}public void testCheckAnswerFailure() {
// ReCaptcha server will return false, followed by the error message on a new line for failure
buildAndCheckAnswer("falsenError Message", false, "Error Message")
}Misc.
CHANGELOG
- 0.4.5 Add code to perform the ReCaptcha functionality - removed recaptcha4j library. Don't add captcha instance to session to avoid serialization issues. Hopefully make it easier to test against.
- 0.4 New version number for Grails 1.1. Same functionality as 0.3.2
- 0.3.2 Moved code into packages. Tried to make licensing easier to discern. Updated to Grails 1.0.4
- 0.3 Added support for environments and new
<recaptcha:ifFailed> tag. Updated to Grails 1.0.3
- 0.2 initial release, developed and tested against Grails 1.0.2
KNOWN ISSUES
- If you are testing locally on a Mac, you may need to change
recaptchaService.verifyAnswer(session, request.getRemoteAddr(), params) to recaptchaService.verifyAnswer(session, "127.0.0.1", params) . This seems to be an issue with the ReCaptcha service not being able to handle the IPV6 localhost identifier.
TODO
Suggestions or Comments
Feel free to submit questions or comments to the Grails users mailing list.
http://grails.org/Mailing+listsAlternatively you can contact me directly - cjohnston at megatome dot com