Заинтересовала меня captcha в java и как ее можно быстро прикрутить к простому
сайту написанному на jsp. Нашел не много информации о jcaptcha, вот теперь хочу
поделиться ей. Давайте напишем простое приложение состоящее из сервлета -
который создает captch'y и проверяет правильность заполнения поля формы у captcha.
Нам понадобится - Apace Tomcat, набор библиотек jakarta-commons 3.2 или выше,
библиотека jcaptcha:
сайту написанному на 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 - проверяет её:
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:
выводит: Поздравляю вы прошли 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 соберется :)
- web application соберется :)
PS.
1) Обратите внимание что jcaptcha - учитывает регистр при вводе
2)При компиляции проги ant я подсовывал в ./lib библиотеку servlet-api.jar
| Вложение | Размер |
|---|---|
| jcaptcha.zip | 18.18 кб |




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