Servlets y Filtros

En posts anterior hemos aprendido como funcionan los servlets, aprendimos también a obtener parámetros desde el cliente incluso aprendimos a utilizar AJAX con servlets.

Pero los servlets no son solo eso, en realidad es solo una parte de la especificación. Por ejemplo, podemos tener filtros que se encargen de ‘filtrar cierta información antes de un suceso’ o listeners para ‘estar atentos ante cualquier evento’. También podemos manejar cookies y sessiones, que veremos más adelante.

Filters (filtros)

Un filtro es una clase especial cuya finalidad es ‘interceptar’ la petición a determinada(s) URLs antes que el servlet se encarge de ella. Es como si estuviese atento a cuando se lance una petición y, antes que el servlet se encarge, el filtro primero se encarga de X proceso, como sanear, comprobar credeciales, etc.

Para comprender a mayor magnitud cómo funcionan los filtros, veremos un ejemplo a continuación.

Precedentes

El contenido de nuestra página es para usuarios registrados, sin embargo, hay algunas páginas como login, acerca y contacto en las cuales no necesitamos de estar registrados ni logueados para tener acceso a ellas.

¿Cómo lo hacemos? Veamos los pasos a continuación

  • Las páginas del sitio estarán en la carpeta misitio dentro de WebContent
  • La página de login estará fuera, ya que no pertenece en sí al sitio
  • Agregaremos a lista blanca las URLs (en misitio) que no requieran acceso
  • El filtro interceptará todas las URLs en el path: /misitio/*. Los paths que no se encuentren en lista blanca, serán redireccionados al login

Ya tenemos de manera general cómo realizar el proceso, ahora solo nos queda codificar.

Nuestra estructura será así:

filters-structure

Dentro del folder misitio creamos las páginas acerca.jsp y contacto.jsp:

misitio/acerca.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="ISO-8859-1">
		<title>Acerca</title>
	</head>
	<body>
	
		<h1>Página de acerca</h1>
	</body>
</html>

misitio/contacto.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="ISO-8859-1">
		<title>Contacto</title>
	</head>
	<body>
		
		<h1>Página de contacto</h1>
	</body>
</html>

Como vemos son páginas demasiado sencillas, solo mostrarán el nombre de la página. Ahora hagamos nuestro login.jsp.

login.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="ISO-8859-1">
		<title>Login</title>
	</head>
	<body>
	
		<h1>Esta es la página de login</h1>
	</body>
</html>

La página de login es también muy sencilla, solo muestra un mensaje. Ahora, hagamos un servlet para cada página JSP. Esto lo hacemos para que puedan observar que se puede filtrar tanto paths sin extensión, como con extensión. Un filtro puede filtrar cualquier tipo de ruta.

LoginServlet.java

package pe.migasoft.tuto.servlets;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet(name="LoginServlet", urlPatterns={"/login"}, asyncSupported=true)
public class Login extends HttpServlet {

	private static final long serialVersionUID = 4634281970858812374L;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
						throws IOException, ServletException {
		
		response.setContentType("text/html");
		
		request.getRequestDispatcher("login.jsp").forward(request, response);
	}
}

Para la página JSP acerca.jsp tendremos los siguentes cambios:

@WebServlet(name="AboutServlet", urlPatterns={"/misitio/acerca"}, asyncSupported=true)
// y avanzamos la petición hacia la página acerca.jsp
request.getRequestDispatcher("/misitio/acerca.jsp").forward(request, response);

Para la página JSP contacto.jsp tendremos los siguientes cambios:

@WebServlet(name="ContactServlet", urlPatterns={"/misitio/contacto"}, asyncSupported=true)
// y avanzamos la petición hacia la página contacto.jsp
request.getRequestDispatcher("/misitio/contacto.jsp").forward(request, response);

Bien. Ya tenemos nuestras páginas webs y nuestros servlets que redigirán hacia las páginas JSP. Por último, hagamos nuestro filtro.

AllowedFilter.java

package pe.migasoft.tuto.filters;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebFilter(filterName="AllowedURLsFilter", asyncSupported = true, urlPatterns = { "/misitio/*" })
public class AllowedFilter implements Filter {

	private static final ArrayList<String> allowedUrls;
	
	static {
		allowedUrls = new ArrayList<>();
		allowedUrls.add("/misitio/acerca");
		allowedUrls.add("/misitio/contacto");
	}
	
    public AllowedFilter() {
        
    }

	public void destroy() {
		
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
						throws IOException, ServletException {

		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		
		String path = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());

		if(allowedUrls.contains(path)) {
			chain.doFilter(request, response);
		}
		else {
			httpResponse.sendRedirect("/ServletFilters/login");
		}
	}

	public void init(FilterConfig fConfig) throws ServletException {
		
	}

}

Vamos a explicar nuestro filtro. Primero creamos una lista que representará nuestra lista blanca. Aquí pondremos las path que no necesitan autenticación. Para esto, debemos interceptar todas las paths para poder comprobar si la path objetivo de la petición no está dentro de la lista blanca. Esto lo hacemos así:

urlPatterns={"/misitio/*"}

Donde * quiere decir todo. En resumen, dice:

Fíltrame todas las rutas luego de /misitio.

La magia ocurre en el método doFilter. Primero se obtiene la path y se comprueba si la path de la petición está en la lista blanca. Si es así, seguimos el flujo natural por medio de chain.doFilter. chain.doFilter comprueba si aún hay otros filtros más, si no los hay, sigue el flujo natural pero si los hay, llama al próximo filtro. En caso la path no esté en la lista blanca, redireccionaremos al login.

Probamos que todo funcione correctamente. Nos dirigimos hacia /misitio/acerca:

filtro-acerca

Si nos dirigimos hacia /misitio/privado veremos que nos redirecciona al login:

filtro-privado

Espero se haya comprendido cómo funcionan los filtros. ¡Nos vemos pronto! 😉

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s