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 example

Source Files

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.