Jeśli w pisanej właśnie przez nas aplikacji J2EE potrzebujemy użyć Captcha'y - czyli prostego zabezpieczenia przed spamrobotami lub złośliwymi automatami, najczęściej sięgamy po bibliotekę JCaptcha lub SimpleCaptcha. Z reguły dość łatwo znaleźć informację i przykłady użycia tych bibliotek z różnymi frameworkami. Obecnie używam RichFaces i w tym akurat przypadku nie udało mi się znaleźć żadnego rozsądnego przykładu. Poniżej opiszę jak udało mi się umieścić (w miarę elegancki sposób jak mi się zdaje) obrazek captchy na jednym z ekranów mojej aplikacji.
Przez chwilę próbowałem JCaptcha'y. Ma świetne możliwości panowania nad generowanym obrazkiem, ale wydała mi się nieco zbyt skomplikowana w użyciu. Może za krótko próbowałem, ale kiedy sięgnąłem po SimpleCaptcha, ta urzekła mnie swoją prostotą ;-).
Głównym założeniem, wynikającym zresztą jasno z wymagań, było to że na tym ekranie musi być użyty Ajax. I fajnie by było gdyby udało się skorzystać jedynie tagów z RichFaces. Na szczęście mamy tag <rich:paint2d>. Wpisujemy więc do kodu naszej strony coś takiego:
<rich:paint2D id="captchaImg" width="#{registerFormBackingBean.captchaWidth}" height="#{registerFormBackingBean.captchaHeight}" format="png" paint="#{registerFormBackingBean.paintCaptcha}" data="#{registerFormBackingBean.captcha}"/>
Dodajemy również do naszego formularza pole w które wpisane ma zostać napis z obrazka Captcha.
Teraz, w naszym backing beanie (czy też jeśli ktoś upiera się na tłumaczenie - w naszym ziarenku wsparcia [błeee];) musimy dodać cztery metody:
getCaptchaWidth()- powinna zwracać szerokość generowanego obrazkagetCaptchaHeight()- powinna zwracać wysokość generowanego obrazkapaintCaptcha()- metoda właściwie generująca obrazekgetCaptcha()- metoda ma zwracać wartość wygenerowaną podczas rendorowania obrazka i służącą jako klucz do cache'a
Metoda paintCaptcha() (proszę zwrócić uwagę, że nie getPaintCaptcha()), musi mieć następujący nagłówek:
void paintCaptcha(java.awt.Graphics2D,java.lang.Object));
Pierwszy argument to obiekt typu java.awt.Graphics2D - niejako "na nim" będziemy "rysować" (generować) obrazek. Drugi, to obiekt przekazany jako wynik metody określonej przez atrybut data.
Moja implementacja tych metod mieszcząca się w backingBeanie wygląda następująco:
public void paintCaptcha(Graphics2D g2d, Object obj) { Captcha captcha = (Captcha)obj; BufferedImage secureImage = captcha.getImage(); if (secureImage == null) { log.warn("Generowanie obrazka CAPTCHA zwróciło NULL"); return; } try { g2d.setClip(0, 0, secureImage.getWidth(), secureImage.getHeight()); g2d.drawImage(secureImage, 0, 0, null); } catch (Exception ex) { log.error("Błąd generowania obrazka CAPTCHA", ex); } } public int getCaptchaWidth() { return CAPTCHA_IMAGE_WIDTH; } public int getCaptchaHeight() { return CAPTCHA_IMAGE_HEIGHT; } public Captcha getCaptcha() { Captcha.Builder captchaBuilder = new Captcha.Builder(CAPTCHA_IMAGE_WIDTH, CAPTCHA_IMAGE_HEIGHT); captchaBuilder.addText(); captchaBuilder.addNoise(new CurvedLineNoiseProducer()); captchaBuilder.addBackground(new GradiatedBackgroundProducer()); captcha = captchaBuilder.build(); return captcha; }
W metodzie getCaptcha() tworzony jest obiekt klasy CaptchaBuilder na którym wykonywane są metody addText() - która generuje losowy napis a następnie umieszcza go na obrazku oraz addNoise() - generującą zakłócenia (można ją wywołać wielokrotnie) oraz addBackground() - przygotowującą tło obrazka. Wynikiem wywołania metody build jest obiekt klasy Captcha. Zapisuję go do zmiennej składowej captcha naszego ziarenka.
Teraz wystarczy już w metodzie obsługującej przycisk wysyłający formularz dokonać sprawdzenia czy tekst wpisany przez użytkownika zgadza się z tym na naszym obrazku captcha. Zakładając, że wpisany w polu formularza napis znajdzie się w zmiennej o nazwie captchaInputText, nasz kod weryfikujący jego poprawność może wyglądać jakoś tak:
if (captcha != null && captcha.isCorrect(captchaInputText)) { log.debug("Poprawnie podany CAPTCHA"); // tutaj obsługujemy dane z naszego formularza // ... } else { log.debug("Nieoprawnie podany CAPTCHA lub CAPTCHA pusty"); // tutaj informujemy użytkownika o błędnie wpisanej wartości // .... }
Przy weryfikacji korzystamy z metody isCorrect() udostępnianej przez instancję klasy Captcha. To już wszystko. Mamy w naszym formularzy dynamicznie generowany obrazek captcha'y.


