Java na webovém serveru: posílání e-mailů a CAPTCHA

Dnes se opět budeme věnovat praktickým ukázkám a naší aplikaci. Po předchozím díle o vlastních JSP značkách a servletech se dnes podíváme na to, jak z Javy na serveru posílat e-maily a jak chránit aplikaci proti spamu pomocí tzv. CAPTCHA.

Seriál: Java na webovém serveru (16 dílů)

  1. Java na serveru: úvod 8.1.2010
  2. Java na webovém serveru: první web 15.1.2010
  3. Java na webovém serveru: práce s databází 29.1.2010
  4. Java na webovém serveru: práce s databází II 12.2.2010
  5. Java na webovém serveru: lokalizace a formátování 19.2.2010
  6. Java na webovém serveru: autorizace a autentizace 26.2.2010
  7. Java na webovém serveru: autorizace a autentizace II 5.3.2010
  8. Java na webovém serveru: porovnání Javy a PHP 10.3.2010
  9. Java na webovém serveru: Vlastní JSP značky a servlety 17.3.2010
  10. Java na webovém serveru: posílání e-mailů a CAPTCHA 24.3.2010
  11. Java na webovém serveru: píšeme REST API 7.4.2010
  12. Java na webovém serveru: SOAP webové služby 14.4.2010
  13. Java na webovém serveru: hlasování a grafy v SVG 28.4.2010
  14. Java na webovém serveru: Komentáře a integrace s Texy 9.6.2010
  15. Java na webovém serveru: AJAX formuláře 23.6.2010
  16. Java na webovém serveru: implementujeme Jabber 30.6.2010

Zatímco pro práci s e-maily si vystačíme se standardními prostředky platformy Java, pro implementaci anti-spamové ochrany budeme muse použít cizí knihovnu. Znalosti servletů probírané minule se nám budou hodit, protože CAPTCHA, kterou dnes použijeme, je založená právě na servletu.

Jen pro připomenutí: jako obvykle si stáhneme aktuální zdrojové kódy z Mercurialu (případně jako bzip2 archiv přes web):

$ hg pull
$ hg up "10. díl"

Posílání e-mailů

Ve webových aplikacích potřebujeme poměrně často posílat e-maily – ať už se jedná o zapomenutá hesla, upozornění správcům nebo třeba registrační e-maily. Vytvoříme si proto univerzální EJB komponentu, která zapouzdří odesílání zpráv, a následně upravíme proces registrace uživatele tak, aby zároveň odeslal upozornění uživateli, že byl zaregistrován.

Pro práci s elektronickou poštou budeme používat standardní JavaMail API. Nakonfigurujeme si proto v aplikačním serveru tzv. JavaMail Session a přiřadíme jí JNDI jméno.

Java 9

Důležité je vyplnit adresu SMTP serveru (v našem případě localhost) a výchozí adresu odesílatele.

V EJB komponentě získáme instanci JavaMail Session jednoduše pomocí anotace @Resource  – nemusíme tak konfigurovat javax.mail.Session ručně v naší aplikaci.

@Resource(lookup = "mail/nekurak.net")
Session smtpRelace;

Pokud bychom např. chtěli odesílat přes jiný SMTP server, stačí překonfigurovat nastavení mail/nekurak.net na úrovni aplikačního serveru a není potřeba zasahovat do aplikace (nasazovaný .war nebo .ear je pořád stejný).

Obecná metoda pro odeslání e-mailu se nachází ve třídě Postak a vypadá následovně:

public void odesliZpravu(Adresa komu, Adresa od, String predmet, String text) throws NekurakVyjimka {

    try {
        MimeMessage mimeZprava = new MimeMessage(smtpRelace);

        mimeZprava.addRecipient(RecipientType.TO, komu.getInternetAddress());
        if (od != null) {
        mimeZprava.setFrom(od.getInternetAddress());
        }
        mimeZprava.setSubject(predmet);
        mimeZprava.setText(text, "UTF-8");

        Transport.send(mimeZprava);
        log.info("Zpráva pro " + komu + " byla odeslána.");
    } catch (Exception e) {
        throw new NekurakVyjimka("Selhalo odesílání e-mailu pro: " + komu, e);
    }
}

Tuto metodu používáme ve třídě UzivatelEJB k odeslání e-mailu uživateli, který se právě zaregistroval (jen tehdy, pokud vyplní e-mail). Zprávy se posílají lokalizované do jazyka, který měl uživatel nastavený ve chvíli vyplňování registračního formuláře.

JMS – ano či ne?

V diskusi pod jedním z předchozích dílů se objevila myšlenka použít pro odesílání e-mailů JMS (Java Message Service). V praxi by to znamenalo, že by naše aplikace nepoužívala klasické JavaMail rozhraní, ale předala by e-mailovou zprávu v podobě objektu do nějaké JMS fronty a zpráva by se „někde jinde“ z JMS převzala a předala SMTP serveru.

Na otázku zda tento přístup uplatnit neexistuje jednoznačná odpověď. Argumentem pro JMS je to, že přijetí e-mailu SMTP serverem může nějakou dobu trvat, což by zdržovalo načtení stránky – takže by mohlo být vhodné použít JMS frontu a předání SMTP serveru provést asynchronně. Na druhou stranu SMTP server na lokálním stroji přijme zprávu prakticky okamžitě a zapojovat do procesu JMS znamená další článek řetězce, který se může pokazit. Záleží tedy hlavně na tom, jakou infrastrukturu máme vybudovanou – pokud nám na serveru běží SMTP server, nemá moc smysl zapojovat JMS. A obráceně: pokud máme fungující JMS systém, nemusíme na server instalovat SMTP server a můžeme použít JMS pro předání zpráv na jiný server, kde SMTP už máme (jenže i v tom případě stačí překonfigurovat JavaMail Session v aplikačním serveru, aby se nespojovala s localhostem, ale s jiným strojem).

Použít JMS pro prosté obalení e-mailů, jako transportní protokol místo SMTP bude ve většině případů nadbytečné. Smysluplnější je nepoužívat JMS pro nízkoúrovňové (technické) události typu „pošli e-mail“, ale pro události obchodního (byznys) charakteru typu „založ uživatele“.

Akademie Root vás zve na školení Základy programovacího jazyka Java a na následné školení Pokročilejší kurz jazyka Java.

CAPTCHA – ochrana proti spamu

Internet je bohužel plný spamerů, a tak je potřeba většinu formulářů chránit proti jejich nevyžádaným reklamám – obvykle pomocí tzv. CAPTCHA (completely automated public Turing test to tell computers and humans apart), což je test, který nám umožní rozlišit legitimní uživatele (živé lidi) od spamovacích robotů.

Kaptcha

Technologie JSP jako taková nemá vestavěnou podporu pro CAPTCHu, je tedy potřeba použít nějakou dodatečnou knihovnu. Jednou z implementací CAPTCHy v Javě je Kaptcha. Na jejím příkladě si ukážeme začlenění proti-spamové ochrany do webové aplikace.

Tato knihovna je otevřený software licencovaný pod Apache 2.0 licencí. Stáhneme si ji z jejích stránek hostovaných na Google Code a přidáme si příslušný .jar do webového modulu aplikace nekurak.net-web.

Kaptcha není jen knihovna, která umí generovat obrázky s různě pokřiveným textem – poskytuje nám i servlet, který slouží ke zpřístupnění těchto obrázků na webu. Tento servlet si aktivujeme přidáním následujících řádků do souboru web.xml:

<servlet>
    <servlet-name>Kaptcha</servlet-name>
    <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Kaptcha</servlet-name>
    <url-pattern>/kaptcha.jpg</url-pattern>
</servlet-mapping>

Do HTML formuláře, který chceme ochránit, pak přidáme CAPTCHu pomocí tohoto kódu:

<img src="kaptcha.jpg" alt="ochrana proti spamu"/>
<label>Opište kód: <input type="text" name="kaptcha" maxlength="255"/></label>

Java 9

Jednoduše vložíme obrázek a políčko formuláře. Servlet při generování obrázku nastavuje atribut relace KAPTCHA_SESSION_KEY na hodnotu, kterou právě vygeneroval. Po odeslání formuláře si tak můžeme zkontrolovat, zda uživatel opsal správný text:

<c:choose>
    <c:when test="${sessionScope['KAPTCHA_SESSION_KEY'] == param.kaptcha}">
    <p class="informacniHlaska">Správně opsaný kód z obrázku.</p>
    </c:when>
    <c:otherwise>
    <p class="chybovaHlaska">Špatně obsaný kód z obrázku.</p>
    </c:otherwise>
</c:choose>

Jelikož se někdy může vygenerovat špatně čitelný text, je dobré dát uživateli možnost přegenerovat si obrázek aniž by musel obnovovat celou stránku. Toho lze dosáhnout tímto kouskem JavaScriptu:

<script type="text/javascript">
    $(function(){
        $('#kaptchaIMG').click(function () { $(this).attr('src', 'kaptcha.jpg?' + Math.floor(Math.random()*100) ); })
    });
</script>

Používáme zde JavaScriptovou knihovnu jQuery, kterou jsme si do naší aplikace přidali už v minulém díle kvůli prohlížečce obrázků. Uživateli tak stačí kliknout na nečitelný obrázek a vygeneruje se mu nový.

Celý příklad naleznete v souboru kaptcha.jsp a vyzkoušet si ho můžete na adrese http://nekurak­.net/kaptcha.jsp.

Knihovna Kaptcha generuje obrázky v poměrně dobré kvalitě (čitelné) a implementovat pomocí ní do svých stránek ochranu proti spamu je snadné. Bohužel ale trpí podobným neduhem jako CAPTCHA na mnoha webech. Pokud si totiž uživatel otevře více stejných formulářů najednou, v proměnné na serveru je uložena pouze hodnota naposledy vygenerovaného obrázku. Když se uživatel pokusí odeslat dříve otevřený formulář, server ho odmítne, přestože uživatel obrázek opsal správně. Řešením by bylo ukládat si všechny v poslední době vygenerované kódy nebo tyto kódy na straně serveru vůbec neukládat a využít místo toho hashování a tajný klíč známý jen serveru.

Závěr

V dnešním díle jsme se naučili posílat e-maily z EJB komponenty a ukázali jsme si, jak ochránit naši aplikaci proti spamu pomocí knihovny Kaptcha. Příště se budeme věnovat tvorbě REST API pro naši aplikaci.

Odkazy

Franta Kučera působí jako Java vývojář na volné noze. Programování je jeho koníčkem už od dětství. Kromě toho má rád Linux, relační SŘBD a XML.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 4

Přehled komentářů

xtonda K těm mailům
František Kučera Re: K těm mailům
xtonda Re: K těm mailům
exception error handling
Zdroj: https://www.zdrojak.cz/?p=3199