JCaptcha JSP совместное ипользование.

Заинтересовала меня captcha в java и как ее можно быстро прикрутить к простому
сайту написанному на jsp. Нашел не много информации о jcaptcha, вот теперь хочу
поделиться ей. Давайте напишем простое приложение состоящее из сервлета -
который создает captch'y и проверяет правильность заполнения поля формы у captcha.
Нам понадобится - Apace Tomcat, набор библиотек jakarta-commons 3.2 или выше,
библиотека jcaptcha:
commons-collections.jar
commons-logging.jar
jcaptcha-1.0-all.jar
Первое нам надо, создать 2 jsp странички:
login.jsp - пусть будет содержать ввод login'a и  paswword'a
+ сдесь же реализован механизм проверки jcaptcha, метод Get - сервлета
simple генерирует капчу, Post -  проверяет её:
<%@ page language="java" %>
<!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" xml:lang="en" lang="en">
<head>
    <title>Using JCaptcha - A Simple Captcha Servlet</title>
</head>
<body>
<h2>Using JCaptcha: A Simple Captcha Servlet</h2>

<form name="SimpleServletForm"
    action="simple" - сервлет обрабатывающий капчу
    method="post">
    1 - е нам нужно получить id сессии и передать его  сервлету simple
    <input type="hidden" name="hidCaptchaID" value="<%= session.getId() %>"/>
    <table border="0" cellspacing="0" cellpadding="3">
        ...
        <tr>
            <td valign="middle">Введите captch'y:<br/>
                <img src="simple" align="middle" border="1"/> -
                2 -е captch'y  возврашает нам сервлет simple
            </td>
            <td>
               <input type="text" name="inCaptchaChars"/> -
               3 - е поле куда вводим сгенерированные captch'ой символы
            </td>
        </tr>
        <tr>
            <td colspan="2" align="right"><input type="submit"
                                                 value="Послать"/>
        </td>
        </tr>
        ...
    </table>
</form>
</body>
</html>
 
страничка results.jsp в зависимости от проверки атрибута PassedCaptcha
выводит: Поздравляю вы прошли Captcha test!
или Sorry, вы не прошли Captcha test - в случае не удачного
забегая вперед скажу что при успешной проверке captcha в методе
Post сервлета simple устанавливается атрибут PassedCaptcha в true
если успешно пройден капча тест иначе false:
<%@ page language="java" %>
<!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" xml:lang="en" lang="en">
<head>
<title>Captcha Demo - Servlet</title>
</head>
<body>
<% Boolean B = (Boolean)session.getAttribute( "PassedCaptcha" );
   if ( B!=null && B.booleanValue() )
   {
%>
  Поздравляю вы прошли Captcha test!
<% } else { %>
  Sorry, вы не прошли Captcha test.
<% } %>
  <p>Please <a href="login.jsp">Try Again</a></p>
</body>
</html>
 
приведу дескриптор развертывания 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>
        <servlet-name>simple</servlet-name>
        <servlet-class>com.vit.SimpleCaptchaServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>simple</servlet-name>
        <url-pattern>/simple</url-pattern>
    </servlet-mapping>
    <!-- welcome file -->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>
</web-app>
 
сам вервлет:
public class SimpleCaptchaServlet extends HttpServlet
{
  String sImgType = null;
  public void init( ServletConfig servletConfig ) throws ServletException
  {
    super.init( servletConfig );

    // проверяем поддерживаются ли типы image  PNG и JPG.
    sImgType = servletConfig.getInitParameter( "ImageType" );
    sImgType = sImgType==null ? "png" : sImgType.trim().toLowerCase();
    if ( !sImgType.equalsIgnoreCase("png") && !sImgType.equalsIgnoreCase("jpg") &&
    !sImgType.equalsIgnoreCase("jpeg") )
    {
      sImgType = "png";
    }
  }

  protected void doGet( HttpServletRequest request, HttpServletResponse response )
  throws ServletException, IOException
  {
    // Создаем капчу
    ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
    byte[] captchaBytes;

    if ( request.getQueryString()!=null )
    {
      response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "GET request should have no query string." );
      return;
    }
    try
    {
      // запрашиваем Session ID который будет в дальнейшем
      // так же идентификатором капчи.
      String captchaId = request.getSession().getId();

      // Генирируем captcha - рисунок.
      BufferedImage challengeImage = CaptchaServiceSingleton.getInstance().getImageChallengeForID(
      captchaId, request.getLocale() );
      ImageIO.write( challengeImage, sImgType, imgOutputStream );
      captchaBytes = imgOutputStream.toByteArray();

      // Сбрасываем flag.
      request.getSession().removeAttribute( "PassedCaptcha" );
    }
    catch( CaptchaServiceException cse )
    {
       System.out.println( "CaptchaServiceException - " + cse.getMessage() );
       response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Problem generating captcha image." );
       return;
    }
    catch( IOException ioe )
    {
       System.out.println( "IOException - " + ioe.getMessage() );
       response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Problem generating captcha image." );
       return;
    }

    //Устанавливаем для 3-х версий протокола http заголовки (мы точно не знаем какой
    //протокол будет использовать пользователь), которые просят не кешировать image(рисунок).
    response.setHeader( "Cache-Control", "no-store" );
    response.setHeader( "Pragma", "no-cache" );
    response.setDateHeader( "Expires", 0 );
    response.setContentType( "image/" + (sImgType.equalsIgnoreCase("png") ? "png" : "jpeg") );

    // Write the image to the client.
    ServletOutputStream outStream = response.getOutputStream();
    outStream.write( captchaBytes );
    outStream.flush();
    outStream.close();
  }

  protected void doPost( HttpServletRequest request, HttpServletResponse response )
  throws ServletException, IOException
  {
    // Проверка капчи
    // Получаем request параметры.
    Map paramMap = request.getParameterMap();
    if ( paramMap.isEmpty() )
    {
      response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Post method not allowed without parameters." );
      return;
    }
    String[] arr1 = (String[])paramMap.get( "hidCaptchaID" );
    String[] arr2 = (String[])paramMap.get( "inCaptchaChars" );
    //проверяем что параметры не пусты и содержат "правильные значения".
    if ( arr1==null || arr2==null  )
    {
      response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Expected parameters were not found." );
      return;
    }

    String sessId = request.getSession().getId();
    String incomingCaptchaId = arr1.length>0 ? arr1[0] : "";
    String inputChars = arr2.length>0 ? arr2[0] : "";

   
    if ( sessId==null || incomingCaptchaId==null || !sessId.equals(incomingCaptchaId) )
    {
      response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Browser must support session cookies." );
      return;
    }

    // Проверяем правильность ввода капчи.
    System.out.println( "Validating - inputChars are: " + inputChars );
    boolean passedCaptchaTest = validateCaptcha(sessId,
            (String) request.getParameter("inCaptchaChars" ));//incomingCaptchaId, inputChars );

    // Установить flag.
    request.getSession().setAttribute( "PassedCaptcha", new Boolean(passedCaptchaTest) );

    //перенаправить  request  на results.jsp page.
    RequestDispatcher rd = getServletContext().getRequestDispatcher( "/results.jsp" );
    rd.forward( request, response );
  }

  private boolean validateCaptcha( String captchaId, String inputChars )
  {
    boolean bValidated = false;
    try
    { //метод проверки капчи возвращает true в случае успеха иначе false
      bValidated = CaptchaServiceSingleton.getInstance().validateResponseForID( captchaId, inputChars );
    }
    catch( CaptchaServiceException cse )
    {}
    return bValidated;
  }
}
 
класс CaptchaServiceSingleton возвращающий методы проверки и генерации картинки(image):
public class CaptchaServiceSingleton {
    private static ImageCaptchaService instance;
    static {
        //1-й парамерт где будут сохранятся значения созданной капчи
        //которые в дальнейшем используются, в методе проверки validateResponseForID(
        //где captchaId - id капчи, inputChars - ввод пользователя);
        //2-й параметр задает класс настроек капчи
        instance = new DefaultManageableImageCaptchaService(
            new FastHashMapCaptchaStore(),
            new MyImageCaptchaEngine(),
            180,
            100000,
            75000);
    }
    public static ImageCaptchaService getInstance(){
        return instance;
    }
}
 
как вы уже поняли самое интересное это класс MyImageCaptchaEngine в котором можно
поиграться с настройками капчи:
public class MyImageCaptchaEngine extends ListImageCaptchaEngine {
     protected void buildInitialFactories() {
         // из каких символов будет состоять наше случайное слово
         WordGenerator wgen = new RandomWordGenerator(
                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789");
         // цвет символа 
         RandomRangeColorGenerator cgen = new RandomRangeColorGenerator(
                 new int[] {10, 150},
                 new int[] {10, 150},
                 new int[] {10, 150});
         // генератор случайного слова
         //  min - кол-во символов в слове, max - кол-во символов в слове, цвет символов
         TextPaster textPaster = new RandomTextPaster(
                    new Integer(3), new Integer(5), cgen, true);
         // генератор цвета фона
         ColorGenerator cg =  new
                 SingleColorGenerator(Color.WHITE);
         //размер по горизонтали фона, размер по вертикали фона, цвет фона
         BackgroundGenerator backgroundGenerator = new FunkyBackgroundGenerator
                    (new Integer(200), new Integer(200),cg);
         //какими шрифтами будут создаваться символы wgen
         Font[] fontsList = new Font[] {
                new Font("Arial", 0, 10),
                new Font("Tahoma", 0, 10),
                new Font("Verdana", 0, 10),
             };
         //min - высота шрифта, max - высота шрифта, набор шрифтов
         FontGenerator fontGenerator = new RandomFontGenerator(
                     new Integer(20), new Integer(100), fontsList);
         // переводим слово в картинку (image)
         WordToImage wordToImage = new ComposedWordToImage(
                     fontGenerator, backgroundGenerator, textPaster);
         this.addFactory(new GimpyFactory(wgen, wordToImage));
     }
}
 
Вот и все, вы можете загрузить проект положить библиотеки в /lib и запустить ant
- web application  соберется :)

PS.

1) Обратите внимание что jcaptcha - учитывает регистр при вводе 

2)При компиляции проги ant я подсовывал в ./lib библиотеку  servlet-api.jar

 

ВложениеРазмер
jcaptcha.zip18.18 кб

Привет, Vit! Есть хорошая

Привет, Vit! Есть хорошая вакансия в Москве. Отправил тебе в личку сообщение, там прямая ссылка на работодателя, можешь писать прямо ему, а можешь через меня. Сам поехать не могу по семейным обстоятельствам. Деньги хорошие даже по Московским меркам.

Отправить комментарий

КАПЧА
Этот вопрос задается для того, чтобы выяснить, являетесь ли Вы человеком или представляете из себя автоматическую спам-рассылку.
CAPTCHA на основе изображений
Enter the characters (without spaces) shown in the image.