Autentizace pomocí filtrů – princip filtrů

18. listopadu 2004

V tomto článku si povíme něco bližšího o filtrech. Vysvětlíme si, co je to filtr, jak jej vytvořit a jak jej nastavit v souboru web.xml. Tyto znalosti budeme potřebovat, až budeme vytvářet filtry pro náš autentizační mechanismus.

Filtr

Při každém příchodu HTTP požadavku je vytvořena instance typu HttpServletRequest, která před tím, než bude dána k dispozici servletu, může projít posloupností filtrů, které mohou instanci modifikovat, nahradit za jinou, nebo dokonce i přesměrovat jinému servletu.

Filtr je instance třídy, která implementuje rozhraní Filter. Rozhraní má tři metody:

  • public void init(FilterConfig filterConfig) throws ServletException – metoda je zavolána při inicializaci filtru. Slouží k nastavení filtru. Parametr metody nám slouží hlavně k získání konfiguračních údajů.
  • public void destroy() – metoda je zavolána při likvidaci filtru.
  • public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException – metoda provádí samotnou činnost filtru. Je-li nastaven filtr na nějaký servlet, bude vždy při požadavku na servlet zavolána právě tato metoda. Jako parametry obdrží HTTP požadavek (HttpServletRequest), HTTP odpověď (HttpServletResponse) a „následovníka“ v řetězci filtrů (FilterChain).

Jak jsem se již zmínil, požadavky a odpovědi mohou projít řetězcem filtrů. Proto každý filtr má jako třetí parametr následovníka v řetězci filtrů. Jestliže již není žádný další filtr v řetězci filtrů, bude požadavek předán požadovanému servletu. Třída implementující rozhraní FilterChain má metodu public void doFilter(ServletRequest request, ServletResponse response) throws java.io.IOException, ServletException, jejíž zavolání předá požadavek a odpověď dalšímu následovníku v řetězci. Předání požadavku a odpovědi následovníkovi musíme zajistit v metodě doFilter sami.

Nastavení filtru

Pro každý servlet (nebo obecně pro jakýkoli zdroj, který lze požadovat) lze nastavit filtr. Filtr se nastavuje v konfiguračním souboru web.xml pomocí elementů filter a filter-mapping. Pravidla pro umístění elementů v dokumentu jsou dána jeho DTD.

Element filter

Element filter slouží k definici filtru. Na základě tohoto elementu bude vytvořena instance filtru. Jak je vidět z DTD, element může obsahovat několik potomků. Nejvýznamnější jsou ty povinné:

  • filter-name – jednoznačný identifikátor filtru.
  • filter-class – název java třídy filtru. Filtr bude instancí této třídy.

Dále je dobré vědět o elementu init-param. Element specifikuje parametry, které mají být předány filtru při jeho inicializaci. Elementů init-param může být v elementu filter libovolný (i nulový) počet. Element init-param má dva povinné potomky:

  • param-name – jméno parametru. Jméno parametru musí být v rámci jednoho filtru jednoznačné.
  • param-value – hodnota parametru.

Rozhraní FilterConfig

Zmínil jsem se o rozhraní FilterConfig. Instance třídy implementující rozhraní FilterConfig je parametrem metody init třídy filtru. Parametr typu FilterConfig je předán filtru při inicializaci. Objekt obsahuje informace o konfiguraci filtru v souboru web.xml. Rozhraní má metody:

  • public java.lang.String getFilterName() – vrací jméno filtru dané obsahem elementu filter-name.
  • public ServletContext getServletContext() – vrátí „aplikaci“, ve které filtr běží.
  • public java.lang.String getInitParameter(java.lang.String name) – vrátí hodnotu parametru (obsah elementu param-value). Parametrem metody je název elementu, který je dán obsahem elementu param-name.
  • public java.util.Enumeration getInitParameterNames() – vrátí výčet jmen všech parametrů filtru. (Vrátí obsahy elementu param-name všech elementů init-param daného filtru.)

Element filter-mapping

Máme tedy inicializován filtr. Nyní ještě musíme určit, na jaké zdroje má být filtr aplikován. K tomu slouží element filter-mapping. Povinnými potomky jsou:

  • filter-name – jméno filtru, který má být aplikován. Obsah elementu musí být shodný s obsahem stejnojmenného elementu v elementu filter.
  • url-pattern nebo servlet-name – určuje masku nebo konkrétní servlet, na který má být filtr aplikován. Element filter-mapping musí obsahovat právě jeden z těchto elementů.

Příklad

Vytvoříme si jednoduchý filtr, který zjistí, jestli je HTTP požadavek typu POST. Jestliže ne, nepropustí požadavek k požadovanému zdroji. Jestliže ano, propustí požadavek a na konec vygenerované stránky vloží nějakou poznámku. U požadavku, který je propouštěn dál, vytvoří nový atribut.

O praktickém využití tohoto filtru by se dalo dost pochybovat. Jedná se jen o ukázkový příklad, na němž chci demonstrovat, že filtr může měnit požadavek, může měnit odpověď, nemusí požadavek propustit dále a podobně.

Metoda doFilter třídy ExampleFilter

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException
{
   HttpServletRequest hrequest = (HttpServletRequest)request;
   HttpServletResponse hresponse = (HttpServletResponse)response;
   response.setCharacterEncoding(„windows-1250“);
   java.io.PrintWriter out = response.getWriter();
   if („POST“.equals(hrequest.getMethod()))
   {
     // Nastavím atribut
     hrequest.setAttribute(„nazev“, „hodnota“);
     // Pustím požadavek dále
     chain.doFilter(hrequest, hresponse);
     // Modifikuji odpověď
     out.println(„<!– Požadavek i odpověď prošly filtrem. –>“);
   }
   else
   { // Požadavek nepropouštím dále, rovnou vytvořím odpověď
     out.println(„<!DOCTYPE HTML PUBLIC \“-//W3C//DTD HTML 4.0 Transitional//EN\“>“);
     out.println(„<html><head><meta http-equiv=\“Content-Type\“ content=\“text/html; charset=windows-1250\“>“);
     out.println(„<title>Vítejte</title></head><body><p>Požadavek není zaslán metodou POST.</p></body></html>“);
   }
}

Konfigurace filtru

Vytvoříme si dvě instance filtru. Podle masky nastavíme každou instanci na jinou oblast a obě instance dohromady na třetí oblast. Část souboru web.xml týkající se filtrů bude vypadat takto:

<filter>
  <filter-name>instance1</filter-name>
  <filter-class>example.ExampleFilter</filter-class>
</filter>
<filter>
  <filter-name>instance2</filter-name>
  <filter-class>example.ExampleFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>instance1</filter-name>
  <url-pattern>/1/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>instance2</filter-name>
  <url-pattern>/2/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>instance1</filter-name>
  <url-pattern>/3/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>instance2</filter-name>
  <url-pattern>/3/*</url-pattern>
</filter-mapping>

K dispozici je vám kompletní zdrojový text společně s ukázkovou aplikací, abyste si filtr mohli sami otestovat.

Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *