Implementing captcha in spring mvc web application example

In this tutorial, let us see that how to implement simple Captcha in Spring MVC web application. In this example, let us implement captcha by creating a login page in Spring. CAPTCHA is a image of letters and numbers used to prevent automated use of pages. The acronym of CAPTCHA is  “Completely Automated Public Turing test to tell Computers and Human Apart”.  Login page that include captcha ensures that human can only login. Now let us see the steps to implement captcha in login page.

Brief Steps:

1. Create login page with captcha
2. Write server side code for generating captcha image and puting in the response.
3. Code to verify whether the captcha string entered by user and stored in the session matches or not.

Project Structure:

captcha project structurecaptcha project structure1

 

Jars Used:

Spring 4 jars, jstl-1.2.jar and  java 1.5 or above

Steps in Detail:

Step 1: Design a web page having the following fields
1. login id
2. password
3. image tag to display captcha
4. input box to accept captcha string
5. refresh button to send request to regenerate the captcha

JSP Code (login.jsp)

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<html>
<head>
<title>Captcha Demo</title>
<style>
.error {
	color: red;
}
</style>

</head>

<body bgcolor="#EAEBEE">

	<form:form action="login" method="post" commandName="login">
		<div class="login">
			<table border="0" align="center">
				<tr>
					<td align="center"><h1>Login</h1></td>
				</tr>
				<tr>
					<td colspan="2"><font color="red"><c:out
								value="${message}"></c:out></font></td>
				</tr>
				<tr>
					<td colspan="2"><form:errors path="userId" cssClass="error" /></td>
				</tr>
				<tr>
					<td>Enter User Id</td>
					<td><form:input path="userId" /></td>
				</tr>
				<tr>
					<td><form:errors path="password" cssClass="error" /></td>
				</tr>

				<tr>
					<td>Enter Password</td>
					<td><form:password path="password" /></td>
				</tr>
				<tr>
					<td>Image#</td>
					<td>
						<div>
							<img id="captcha_id" name="imgCaptcha" src="captcha.jpg">
						</div>
					</td>

					<td align="left"><a href="javascript:;"
						title="change captcha text"
						onclick="document.getElementById('captcha_id').src = 'captcha.jpg?' + Math.random();  return false">
							<img src="images/refresh.png" />
					</a></td>

				</tr>
				<tr>
					<td colspan="2"><form:errors path="captcha" cssClass="error" /></td>
				</tr>

				<tr>
					<td>Enter above Image text#</td>
					<td><form:input path="captcha" /></td>
				</tr>

				<tr>
					<td colspan="2" align="center"><input type="submit"
						value="Login" /></td>
				</tr>

			</table>
		</div>

	</form:form>

</body>
</html>

Step 2: Write model code (Login.java) for mapping the fields of login page.

package net.javaonline.login.form;
public class Login {

	private String userId;
	private String password;
	private String captcha;
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getCaptcha() {
		return captcha;
	}
	public void setCaptcha(String captcha) {
		this.captcha = captcha;
	}
} 

Step 3Write Servlet code to generate Captcha string, converting the text to image and writing to response as binary data.

CaptchaGenServlet.java

package net.javaonline.captcha.servlet;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import javax.servlet.http.*;

import java.io.*;

import net.javaonline.captcha.util.Util;

public class CaptchaGenServlet extends HttpServlet {

         public static final String FILE_TYPE = "jpeg";

        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {

            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Max-Age", 0);

        	String captchaStr="";

		//captchaStr=Util.generateCaptchaTextMethod();

        	captchaStr=Util.generateCaptchaTextMethod2(6);

            try {

            	int width=100;     	int height=40;

            	Color bg = new Color(0,255,255);
            	Color fg = new Color(0,100,0);

            	Font font = new Font("Arial", Font.BOLD, 20);
            	BufferedImage cpimg =new BufferedImage(width,height,BufferedImage.OPAQUE);
            	Graphics g = cpimg.createGraphics();

            	g.setFont(font);
                g.setColor(bg);
                g.fillRect(0, 0, width, height);
                g.setColor(fg);
            	g.drawString(captchaStr,10,25);   

                HttpSession session = request.getSession(true);
                session.setAttribute("CAPTCHA", captchaStr);

               OutputStream outputStream = response.getOutputStream();

               ImageIO.write(cpimg, FILE_TYPE, outputStream);
               outputStream.close();

            } catch (Exception e) {
                    e.printStackTrace();
            }
        }

        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
        	doPost(request, response);
        }

 }

Step 4: Write java code to generate random text. The following Util.java class contains two methods to generate random text. You can call any method. In our example, method 2 is called.

Util.java

package net.javaonline.captcha.util;

import java.util.Random;

public class Util {

public static String generateCaptchaTextMethod1() 	 {

	   	Random rdm=new Random();
		int rl=rdm.nextInt(); // Random numbers are generated.
		String hash1 = Integer.toHexString(rl); // Random numbers are converted to Hexa Decimal.

		return hash1;

}

public static String generateCaptchaTextMethod2(int captchaLength) 	 {

	 String saltChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
	 StringBuffer captchaStrBuffer = new StringBuffer();
	        java.util.Random rnd = new java.util.Random();

	        // build a random captchaLength chars salt
	        while (captchaStrBuffer.length() < captchaLength)
	        {
	            int index = (int) (rnd.nextFloat() * saltChars.length());
	            captchaStrBuffer.append(saltChars.substring(index, index+1));
	        }

	    return captchaStrBuffer.toString();

}

}

Step 5:

Write Controller class to load login page and process login page. In the Processing part, we have to check whether the Captcha entered by the user matches with the Captcha stored in the session.

The controller code is given below

package net.javaonline.captcha.controller;
import javax.servlet.http.HttpSession;
import net.javaonline.login.form.Login;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class LoginController {

@RequestMapping(value="/loadLoginPg")
	public String homepage(Model model){
		Login login= new Login();
		model.addAttribute("login", login);
		return "login";
}

@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@ModelAttribute("login") Login login,BindingResult result,Model model,HttpSession session) {

	if (login.getUserId()==null || login.getUserId().equals(""))
		{
		  	login.setCaptcha("");
	    	model.addAttribute("message", "User Id is required");
	    	return "login";
		}

	if (login.getPassword()==null || login.getPassword().equals(""))
	{
	  	login.setCaptcha("");
    	model.addAttribute("message", "Password is required");
    	return "login";
	}	

	 String captcha=(String)session.getAttribute("CAPTCHA");
	    if(captcha==null || (captcha!=null && !captcha.equals(login.getCaptcha()))){
	    	login.setCaptcha("");
	    	model.addAttribute("message", "Captcha does not match");
	    	return "login";
	    }

		if(login.getUserId().equals("guest") && login.getPassword().equals("ddd")){
			System.out.println("user id and password matches");
			model.addAttribute("loginId", login.getUserId());
			return "home";

		}
		else{
			login.setCaptcha("");
			model.addAttribute("message","User ID or Password Incorrect");
			return "login";
		}

}
}

Step 6: Design a page (home.jsp) that is to be opened if the login is success

home.jsp


<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Home</title>
</head>
<body>
	  Login Success. Welcome to ${loginId}
</body>

</html>

Step 7: Now copy the following XML files to your project.

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >

  <servlet>
    <servlet-name>Captcha</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/Captcha-Context.xml</param-value>
      </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

    <servlet>
    <servlet-name>CaptchaServlet</servlet-name>
    <servlet-class>net.javaonline.captcha.servlet.CaptchaGenServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CaptchaServlet</servlet-name>
    <url-pattern>/captcha.jpg</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>Captcha</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

Captcha-Context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:mvc="http://www.springframework.org/schema/mvc"
      xmlns:tx="http://www.springframework.org/schema/tx"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.1.xsd">

      <context:component-scan base-package="net.javaonline.captcha.controller"/>
	  <mvc:annotation-driven />
	  <mvc:resources mapping="/images/**" location="/images/" />
	  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/MyPages/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>
 

Run the project by calling the URL

http://localhost:8080/SpringCaptcha/loadLoginPg

login page with captcha

login submit1

 

Enter wrong captcha and login

login captcha mismatch

login submit2

 

Enter correct userid, password and captcha then login

 

springcaptcha result

 

You may also like

Leave a Reply