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.