JSF PrimeFaces CAPTCHA Code Example
The JSF PrimeFaces CAPTCHA code example shows you how to protect JSF PrimeFaces Sign Up and Login forms with BotDetect CAPTCHA library.
We will build a simple tabbed Sign Up/Login form using PrimeFaces TabView component.
To keep the example code simple, the example doesn't connect to a data store in order to persist data or authenticate/authorize user. To see how example works, just use "admin" as both username and password on Login form.
Download the BotDetect Java CAPTCHA Generator archive to run this exampleSource Files
- index.xhtml
- WEB-INF/src/com/captcha/botdetect/examples/jsf/primefaces_captcha/view/LoginForm.java
- WEB-INF/src/com/captcha/botdetect/examples/jsf/primefaces_captcha/view/SignupForm.java
- resources/js/scripts.js
- WEB-INF/web.xml
Running Example
In case you are making this example from scratch in your IDE, you need to ensure botdetect.jar
, botdetect-servlet.jar
, botdetect-jsp20.jar
, and botdetect-jsf20.jar
are in the classpath.
index.xhtml
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:botDetect="https://captcha.com/java/jsf"> <h:head> <title>BotDetect Java CAPTCHA Validation: JSF PrimeFaces CAPTCHA Code Example</title> <h:outputStylesheet name="stylesheet.css" library="css"/> <h:outputScript name="scripts.js" library="js"/> </h:head> <h:body> <div class="column form-container"> <h1>BotDetect Java CAPTCHA Validation:<br/> JSF PrimeFaces CAPTCHA Code Example</h1><br/> <p:tabView cache="false" dynamic="true"> <p:tab title="Sign Up"> <h:panelGrid columns="2"> <h:form id="signupForm"> <p:growl id="signup_growl" sticky="true" showDetail="true" life="3000" /> <h:panelGrid columns="1" cellpadding="5"> <h:outputLabel for="username" value="Username:" /> <p:inputText id="signup_username" value="#{jsfPrimefacesSignupForm.username}" required="true" label="username" /> <h:outputLabel for="email" value="Email:" /> <p:inputText type="email" id="signup_email" value="#{jsfPrimefacesSignupForm.email}" required="true" label="email" /> <h:outputLabel for="password" value="Password:" /> <p:password id="signup_password" value="#{jsfPrimefacesSignupForm.password}" required="true" label="password" /> <h:outputLabel for="captchaCode" value="Retype the characters from the picture:" /> <botDetect:jsfCaptcha id="jsfPrimefacesSignupFormCaptcha" userInputID="signup_captchaCode" imageWidth="180" imageHeight="50" binding="#{jsfPrimefacesSignupForm.captcha}"/> <p:inputText id="signup_captchaCode" label="captchaCode" value="#{jsfPrimefacesSignupForm.captchaCode}"/> <p:commandButton id="signupFormButton" value="Sign Up" update="signup_growl" action="#{jsfPrimefacesSignupForm.signup}" oncomplete="handleSignupRequest(xhr, status, args)" /> </h:panelGrid> </h:form> </h:panelGrid> </p:tab> <p:tab title="Login"> <h:form id="loginForm"> <p:growl id="login_growl" sticky="true" showDetail="true" life="3000" /> <h:panelGrid columns="1" cellpadding="5"> <h:outputLabel for="username" value="Username:" /> <p:inputText id="login_username" value="#{jsfPrimefacesLoginForm.username}" required="true" label="username" /> <h:outputLabel for="password" value="Password:" /> <p:password id="login_password" value="#{jsfPrimefacesLoginForm.password}" required="true" label="password" /> <h:outputLabel for="captchaCode" value="Retype the characters from the picture:" /> <botDetect:jsfCaptcha id="jsfPrimefacesLoginFormCaptcha" userInputID="login_captchaCode" imageWidth="180" imageHeight="50" binding="#{jsfPrimefacesLoginForm.captcha}"/> <p:inputText id="login_captchaCode" label="captchaCode" value="#{jsfPrimefacesLoginForm.captchaCode}"/> <p:commandButton id="loginFormButton" value="Login" update="login_growl" action="#{jsfPrimefacesLoginForm.login}" oncomplete="handleLoginRequest(xhr, status, args)" /> </h:panelGrid> </h:form> </p:tab> </p:tabView> </div> </h:body> </html>
We use PrimeFaces TabView component to build a simple tabbed Sign Up and Login form and add Captcha challenge to these forms using BotDetect custom jsfCaptcha
tag.
LoginForm.java
package com.captcha.botdetect.examples.jsf.primefaces_captcha.view; import com.captcha.botdetect.web.jsf.JsfCaptcha; import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import javax.faces.context.FacesContext; import org.primefaces.PrimeFaces; @ManagedBean(name="jsfPrimefacesLoginForm") @RequestScoped public class LoginForm { private String username; private String password; private String captchaCode; private JsfCaptcha captcha; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getCaptchaCode() { return captchaCode; } public void setCaptchaCode(String captchaCode) { this.captchaCode = captchaCode; } public JsfCaptcha getCaptcha() { return this.captcha; } public void setCaptcha(JsfCaptcha captcha) { this.captcha = captcha; } public void login() { FacesMessage message = null; boolean loggedIn = false; // validate the Captcha to check we're not dealing with a bot boolean isHuman = captcha.validate(captchaCode); if (isHuman) { if ((username != null) && (username.equals("admin")) && (password != null) && (password.equals("admin"))) { loggedIn = true; // TODO: do what you want here // like log the user, redirect the user to other page message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Welcome", "You successfully logged in to this site"); } else { loggedIn = false; message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Login Error", "Invalid credentials"); } } else { loggedIn = false; message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Login Error", "Please enter a valid Captcha code"); } this.captchaCode = ""; FacesContext.getCurrentInstance().addMessage(null, message); PrimeFaces.current().ajax().addCallbackParam("loggedIn", loggedIn); } }
Binding JsfCaptcha
tag from JSF Login form with backing bean property allows us to dynamically set Captcha properties and to perform Captcha validation in backing bean's form action method.
SignupForm.java
package com.captcha.botdetect.examples.jsf.primefaces_captcha.view; import com.captcha.botdetect.web.jsf.JsfCaptcha; import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import javax.faces.context.FacesContext; import org.primefaces.PrimeFaces; @ManagedBean(name="jsfPrimefacesSignupForm") @RequestScoped public class SignupForm { private String username; private String password; private String email; private String captchaCode; private JsfCaptcha captcha; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getCaptchaCode() { return captchaCode; } public void setCaptchaCode(String captchaCode) { this.captchaCode = captchaCode; } public JsfCaptcha getCaptcha() { return captcha; } public void setCaptcha(JsfCaptcha captcha) { this.captcha = captcha; } public void signup() { FacesMessage message = null; boolean signupSuccess = false; // validate the Captcha to check we're not dealing with a bot boolean isHuman = captcha.validate(captchaCode); if (isHuman) { if ((username != null) && (email != null) && (password != null)) { signupSuccess = true; // TODO: do what you want here // such as save data into database, sendmail, etc. message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Signup Success", "Thank you for signing up!"); } else { signupSuccess = false; message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Signup Error", "Please enter valid values"); } } else { signupSuccess = false; message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Signup Error", "Please enter a valid Captcha code"); } this.captchaCode = ""; FacesContext.getCurrentInstance().addMessage(null, message); PrimeFaces.current().ajax().addCallbackParam("signupSuccess", signupSuccess); } }
Just like Login form above, we also bind JsfCaptcha
tag from JSF Sign up form with backing bean property.
scripts.js
function handleSignupRequest(xhr, status, args) { if (args.validationFailed) { // primefaces UI validation failed return; } // we should reload captcha image after server-side validation is completed // in order to update new captcha code for current instance id var captcha = window["jsfPrimefacesSignupFormCaptcha"]; captcha.ReloadImage(); } function handleLoginRequest(xhr, status, args) { if (args.validationFailed) { // primefaces UI validation failed return; } // we should reload captcha image after server-side validation is completed // in order to update new captcha code for current instance id var captcha = window["jsfPrimefacesLoginFormCaptcha"]; captcha.ReloadImage(); }
In the snippet above, we created PrimeFaces client side callback functions for Login and Sign Up forms which will be invoked when ajax request is completed.
Once request is completed, we need to reload Captcha by calling the ReloadImage()
function of the captcha
JavaScript object. This is mandatory in order to generate a new captcha code for the current captcha id.
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>JavaServerFaces</display-name> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <context-param> <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name> <param-value>true</param-value> </context-param> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> <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> <welcome-file-list> <welcome-file>faces/index.xhtml</welcome-file> </welcome-file-list> <session-config> <session-timeout> 30 </session-timeout> </session-config> </web-app>
In WEB-INF/web.xml
file we register CaptchaServlet
used for BotDetect Captcha requests.
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