Java Servlets – servlet filtering
V tomto článku sa zameriame na podpornú technológiu súvisiacu nie len so servletmi ale aj so stránkami JSP. Pôjde o systém filtrovania informácií resp. prichádzajúcich požiadaviek a následného vyhodnocovania týchto údajov. V závislosti na výsledku vyhodnocovania sa vykoná preddefinovaná činnosť. Servlet filtering poskytuje štandardizovanú alternatívu k neštandartnému systému tzv. „reťazenia servletov“ (servlet chaining).
Hneď na začiatok musím upozorniť, že filtre priniesla až verzia Java Servlets 2.3. Na serveroch nepodporujúcich túto verziu filtre nebudú funkčné. Filter je v podstate program bežiaci na strane servera, ktorý sa vykonáva ešte pred samotným servletom s ktorým je asociovaný. Pričom filter môže byť asociovaný s viacerými servletmi. Úlohou filtra je zväčša prečítať si informácie z objektu request
a následne vykonať niektorú z týchto možností:
- Predať riadenie servletu úplne normálne bez zmeny.
- Predať riadenie servletu s modifikovanými informáciami objektu request.
- Predať riadenie servletu s modifikáciou objektu response.
- Presmerovať požiadavku na iný servlet ako ten asociovaný s filtrom, vrátiť niektorý status kód alebo vygenerovať vlastný výstup.
Pomocou filtrov môžete napríklad obmedziť prístup k vybraným stránkam pre vybraných uživateľov, z jedného miesta (filter) robiť zmeny v mnohých servletoch a pod. Skrátka môžete zapuzdriť určité chovanie do externej komponenty, ktorú je možné ľubovoľne využiť.
Vytvorenie filtra
Vytvorenie filtra si rozdelíme do piatich krokov:
- Vytvorenie triedy filtra implementujúcej javax.servlet.Filter – toto rozhranie obsahuje iba tri metódy. Metóda
init()
zabezpečuje inicializáciu filtra a ako vstupný parameter akceptuje objekt triedyFilterConfig
. Servlet kontajner zavolá túto metódu iba raz; pri vytváraní inštancie filtra. MetódadoFilter()
vykonáva samotné filtrovanie. Ako parametre akceptuje objekty triedServletRequest, ServletResponse
aFilterChain
, všetky z balíčka javax.servlet. Posledná metóda jedestroy()
, ktorá má za úlohu „upratať“ všetky držané zdroje. Jej význam je podobný ako význam rovnomennej metódy v triede javax.servlet.Servlet. - Vloženie logiky filtrovania do metódy doFilter() – ako som uviedol, prvým argumentom metódy
doFilter()
je objekt request. Môžeme z neho získať formulárové dáta, cookies, obsah hlavičky protokolu HTTP a pod. Druhý argument objekt response sa v prevažnej miere ignoruje, ale existujú dva prípady kedy by ste ho mohli využiť. Tretí argument je objektFilterChain
, ktorého použitie je vysvetlené v nasledujúcom kroku. - Zavolanie metódy doFilter() objektu FilterChain – ako som už spomenul metóda
doFilter()
rozhrania Filter akceptuje FilterChain ako jeden z argumentov. Ak zavoláte metódudoFilter()
tohto objektu bude spustený ďalší asociovaný filter. Ak žiadny ďalší filter nie je asociovaný so servletom prípadne s JSP, potom je proces predaný samotnému servletu. Nezabudnite, že úplne na začiatku tu bola požiadavka smerovaná na servlet (JSP). Ale prv ako by sa mu predalo riadenie vykoná sa filter. A filtrov môže byť pre jeden servlet viac. - Priradenie filtra k servletu – na tento účel sa v deskriptore
web.xml
používajú dva elementy<filter>
a<filter-mapping>
. - Zablokovanie priameho prístupu k servletu – možno to vyzerá nezmyselne ale treba si uvedomiť aj stránku zabezpečenia aplikácie. Ak užívateľ má možnosť obísť použitie filtra môže sa o to pokúsiť. Preto treba tejto možnosti zabrániť.
V bode 2. som uviedol, že existujú dva dôvody kedy by ste druhý argument metódy doFilter()
objekt response
mohli potrebovať. Prvý je ten keď potrebujete úplne zablokovať prístup k asociovanému servletu. Vtedy môžete využiť response.getWriter()
a rovno poslať klientovi odpoveď. Druhý dôvod je prípad ak chcete modifikovať výstup vygenerovaný servletom. Na tento účel je však treba vytvoriť špeciálnu triedu zdedenú od HttpServletResponseWrapper
.
Zaregistrovanie filtra
Spomínal som, že na tento účel je nutné zeditovať deskriptor web.xml. Hlavným elementom je <filter>
. Musí byť umiestnený ešte pred akýmkoľvek <servlet>
, <servlet-mapping>
, alebo <filter-mapping>
elementom. Obsahuje niekoľko subelementov pričom najdôležitejšie sú tieto tri:
- <filter-name> – tento element je vyžadovaný a predstavuje meno pod ktorým bude filter zaregistrovaný
- <filter-class> – je takisto povinný a obsahuje plne kvalifikovaný názov triedy filtra
- <init-param> – toto je voliteľný element ktorý je možné prečítať metódou
FilterConfig.getInitParameter()
. Na rozdiel od dvoch predchádzajúcich sa môže tento element vyskytovať v jednom filtri viackrát.
<?xml version=“1.0″ encoding=“ISO-8859-1″?>
<!DOCTYPE web-app PUBLIC
„-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN“
„http://java.sun.com/dtd/web-app_2_3.dtd“>
<web-app>
<filter>
<filter-name>Filter</filter-name>
<filter-class>package.FilterClass</filter-class>
</filter>
</web-app>
Asociovanie filtra so servletom
Na vytvorenie dvojice filter-servlet použijeme element <filter-mapping>
, ktorý musí byť umiestnený až za elementom <filter>
ale pred elementom <servlet>
. Obsahuje tieto tri subelementy:
- <filter-name> – má rovnaký význam ako pri elemente filter. Musí obsahovať rovnaký názov filtra
- <url-pattern> – deklaruje tvar URL začínajúci na (/) na ktorý sa má filter aplikovať
- <servlet-name> – obsahuje názov servletu tak ako je zaregistrovaný v deskriptore web.xml, na ktorý sa má aplikovať filter
<?xml version=“1.0″ encoding=“ISO-8859-1″?>
<!DOCTYPE web-app PUBLIC
„-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN“
„http://java.sun.com/dtd/web-app_2_3.dtd“>
<web-app>
<filter-mapping>
<filter-name>Filter</filter-name>
// buď použijete …
<url-pattern>/aplication/MyServlet</url-pattern>
// alebo …
<servlet-name>MyServlet</servlet-name>
</filter-mapping>
</web-app>
Zablokovanie priameho prístupu k servletu
V 5. bode som načrtol myšlienku, že existuje teoretická možnosť aby sa užívateľ pokúsil obísť použitie filtra. Inak povedané máme servlet zaregistrovaný a namapovaný na nejaké url. Na toto url alebo na meno servleta máme asociovaný filter.
<?xml version=“1.0″ encoding=“ISO-8859-1″?>
<!DOCTYPE web-app PUBLIC
„-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN“
„http://java.sun.com/dtd/web-app_2_3.dtd“>
<web-app>
<filter>
<filter-name>Filter</filter-name>
<filter-class>package.FilterClass</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter</filter-name>
<servlet-name>MyServlet</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>interval.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>
</web-app>
Všetko bude OK ak klient požiada o takéto url http://host:port/webapp/myservlet
. Vtedy sa na servlet MyServlet aplikuje filter. Avšak ak užívateľ zadá http://host:port/webapp/servlet/interval.MyServlet
podarí sa mu použitie filtra obísť. Ako si s tým poradiť? Máme dve možnosti pričom obidve predpokladajú použitie špeciálneho „error“ servletu. Pri prvej zaregistrujeme tento error servlet pod týmto url pattern-om /servlet/*
čo znamená, že všetky pokusy smerujúce na túto adresu budú presmerované na error servlet. Druhá možnosť je podobná s tým rozdielom, že url pattern sa bude vzťahovať na konkrétny servlet. Ak však potrebujete takto zabezpečiť viac servletov je nutné urobiť to pre každý zvlášť.
Príklad
TimeFilter.java: Treba si pozrieť hlavne metódy init()
a doFilter()
. Prostredníctvom prvej získam z deskriptoru web.xml dva inicializačné parametre: názov firmy a šablónu podľa ktorej sa má zobrazovať dátum a čas. Výhodou tohto prístupu je, že pri zmene firmy alebo dátumovej šablóny nie je nutné editovať zdrojový kód servletu a znova robiť deployment. Z toho vyplývajú menšie náklady na údržbu aplikácie. V metóde doFilter()
získam objekt PrintWriter
a priamo zapíšem dátum a čas na výstup objektu response
. Ďalej vezmem parameter názvu firmy a vložím ho do objektu request
ako atribút. Nie je možné priamo nastaviť alebo zmeniť parametre objektu request
, je možné ich len prečítať. Teda neexistuje metóda typu setParameter()
.
TimeServlet.java: Po spracovaní filtra sa vykoná servlet. V ňom iba za predpokladu, že nie je null, prečítam atribút obsahujúci informáciu o firme a vložím ho do výstupu. Servlet ešte vypíše priamy odkaz na seba aby ste videli výsledok zablokovania priameho prístupu.
ErrorServlet.java: Je to len primitívny servlet ktorý vypíše upozornenie a poskytne správny odkaz. Na koniec ešte prikladám výpis z web.xml potrebný na správne fungovanie príkladu.
Príklad si môžete skúsiť tiež on-line alebo si ho stiahnuť ako zip. Neukázali sme si všetky možnosti ktoré filtre poskytujú, ale to ani nebolo náplňou tohto článku.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Umělá inteligence v IT
27. září 2023 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024
IvoHaSw
Zář 12, 2009 v 7:08V ErrorServlet.java by mělo být místo:
out.println(„Použite prosím tento odkaz„);
toto
out.println(„Použite prosím tento odkaz„);
Pak to funguje