Uno de los conceptos que más problemas produce cuando comenzamos a trabajar con aplicaciones web en Java es el concepto de java session (HttpSession) que sirve para almacenar información entre diferentes peticiones HTTP ya que este protocolo es stateless (sin estado). Así pues en muchas ocasiones nos encontraremos con el problema de compartir estado (datos usuario) entre un conjunto amplio de páginas de nuestra Aplicación.
Java Session
Para solventar este problema en la plataforma Java EE se usa de forma muy habitual la clase HttpSession que tiene una estructura de HashMap (Dicccionario) y permite almacenar cualquier tipo de objeto en ella de tal forma que pueda ser compartido por las diferentes páginas que como usuarios utilizamos.
Funcionamiento
El funcionamiento del sistema de sessiones es relativamente sencillo. Cada vez que un usuario crea una session accediendo a una página (que la genere) se crea un objeto a nivel de Servidor con un HashMap vacío que nos permite almacenar la información que necesitamos relativa a este usuario. Realizado este primer paso se envía al navegador del usuario una Cookie que sirve para identificarle y asociarle el HashMap que se acaba de construir para que pueda almacenar información en él. Este HashMap puede ser accedido desde cualquier otra página permitiéndonos compartir información.
Usuarios y Sessiones
El concepto de Session es individual de cada usuario que se conecta a nuestra aplicación y la información no es compartida entre ellos. Así pues cada usuario dispondrá de su propio HashMap en donde almacenar la información que resulte útil entre páginas.
Un ejemplo sencillo
Vamos a ver un ejemplo utilizando dos Servlets básicos en el cual un servlet almacena datos en la sessión (concretamente un objeto producto) y otro servlet lee los datos de la session y los muestra por pantalla.
</p> <p>package com.arquitecturajava;</p> <p>public class Producto {</p> <p>private int id;<br> private String concepto;<br> private double importe;<br> public int getId() {<br> return id;<br> }<br> public void setId(int id) {<br> this.id = id;<br> }<br> public String getConcepto() {<br> return concepto;<br> }<br> public void setConcepto(String concepto) {<br> this.concepto = concepto;<br> }<br> public double getImporte() {<br> return importe;<br> }<br> public void setImporte(double importe) {<br> this.importe = importe;<br> }<br> public Producto(int id, String concepto, double importe) {<br> super();<br> this.id = id;<br> this.concepto = concepto;<br> this.importe = importe;<br> }<br> public Producto() {<br> super();<br> }</p> <p>}</p> <p>
</p> <p>package com.arquitecturajava;</p> <p>import java.io.IOException;<br> import java.io.PrintWriter;</p> <p>import javax.servlet.ServletException;<br> import javax.servlet.annotation.WebServlet;<br> import javax.servlet.http.HttpServlet;<br> import javax.servlet.http.HttpServletRequest;<br> import javax.servlet.http.HttpServletResponse;<br> import javax.servlet.http.HttpSession;</p> <p>@WebServlet("/CrearSession")<br> public class CrearSession extends HttpServlet {<br> private static final long serialVersionUID = 1L;</p> <p>protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {</p> <p>HttpSession misession= request.getSession(true);<br> Producto miproducto= new Producto(1,"telefono",300);<br> misession.setAttribute("producto",miproducto);<br> PrintWriter pw= response.getWriter();<br> pw.println("<html><body>Producto en session</body></html>");<br> pw.close();</p> <p>}<br> }</p> <p>
</p> <p>package com.arquitecturajava;</p> <p>import java.io.IOException;<br> import java.io.PrintWriter;</p> <p>import javax.servlet.ServletException;<br> import javax.servlet.annotation.WebServlet;<br> import javax.servlet.http.HttpServlet;<br> import javax.servlet.http.HttpServletRequest;<br> import javax.servlet.http.HttpServletResponse;<br> import javax.servlet.http.HttpSession;</p> <p>@WebServlet("/VerSession")<br> public class VerSession extends HttpServlet {<br> private static final long serialVersionUID = 1L;</p> <p>protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br> HttpSession misession= (HttpSession) request.getSession();</p> <p>Producto miproducto= (Producto) misession.getAttribute("producto");</p> <p>PrintWriter pw= response.getWriter();<br> pw.println("<html><body>"+ miproducto.getId()+ "," +miproducto.getConcepto()+","+ miproducto.getImporte());<br> pw.close();<br> }<br> }</p> <p>
En este caso el primer Servlet (CreaSession) se encarga de crear la session y almacenar un producto en ella. Mientras el segundo Servlet se encargará de acceder a los datos y mostrarlos por pantalla.
Una vez invocado el Servlet que crea la session invocamos a VerSession y nos mostrará por pantalla los datos que se han introducido.
Hemos compartido información perteneciente al mismo usuario entre dos Servlets. Recordemos que no se debe abusar del almacenamiento de objetos en Session ya que al ser por cada usuario si tenemos muchos usuarios concurrentes estaremos obligando al servidor a utilizar mucha memoria para almacenarlos.
Otros artículos relacionados : ServletContext, Java Filter , ServletContextListener
Hola Cecilio, mil gracias por este espacio y por compartir tu conocimiento y tu experiencia me puedes ayudar con esta duda como se calculan los límites de un servidor java para sesiones activas es un aplicativo web echo con jsp y publicado en payara5 en Amazon como puedo mejorar este tipo de servidores para aumentar las sesiones sin cambiar de tecnología
uhhm es una buena pregunta . Probablemente reduciendo el espacio que ocupan los objetos en sessión. O teniendo varios servidores por afinidad
tengo una aplicación montada en apache tomcat en el puerto 8080, asi que;
cuando terminaba mi sesion me redirecionaba al “localhost:8080/MyApp/login/”
Me solicitaron cambiar el puerto al 443, y ahora no funciona el redirecionamiento, hace lo siguiente:
cuando terminaba mi sesion me redirecionaba al “localhost/MyApp/login/” (sin el puerto, y por ende me marca error en la pagina, tengo yo que ponerle “:443” para corregir la URL.
Estoy usando Java 8, Apache Tomcat 8.0.27, Spring Security, NetBeans 8.2.
Espero me puedan ayudar,
De antemano gracias!
Saludos
Buenas Cecilio, tengo una duda en cuanto a cierre de sesión, en una página JSF se accede por un login y se crea sesión para un usuario, pero al cerrar la pestaña del navegador directamente pues la sesión no muere por que no se ha llamado al session.invalidate(), he intentado detectar el cierre de la pestaña por medio de javascript y así poder hacer algo para terminar la sesión pero no me funciona bien del todo, que pudiera hacer en este caso? agradezco tu atención.
la verdad es que son temas un poco border line , no te funciona con los eventos de Javacript? . A mi se me ocurre q puede pasar lo siguiente….pero no lo he probado . Puede ser que al cerrar la ventana no de tiempo a realizar la peticion ajax de cieerre . Que tal realizar en el unload o evento similar una peticion ajax y sacar un alert de session cerrada… de esa manera igual si da tiempo
Hola Cecilio!,
muy bueno tu sitio.
te hago una breve consulta sobre las sesiones en java, estoy desarrollando una aplicacion usando el modelo servlet/jsp.
Necesito que sea multi-empresa, que me maneje informacion de varias empresas.
Por ahora estoy usando variables de tipo session, pero me topo con el problema de que si el usuario me abre una segunda pestaña del browser y accede a la aplicacion y quiere tener 2 empresas al mismo tiempo abiertas, una en cada pestaña del browser, se me mezclan las sesiones !
Alguna idea de como puedo manejar esto?
Gracias de antemano!
Mira ese es el comportamiento por defecto ya lo siento. Si quisieras otra cosa mi consejo es generar un filtro a nivel de servlets y que ese filtro de de alta una cokkie diferente por empresa así simularias dos sesiones simultaneas
que use otro navegador, es mas facil para el usuario y simula tener 2 dispositivos ya que las peticiones Http son diferentes.
Si eso siempre es posible claro, pero queda raro
Buenas, tengo un problema con una JSF donde se encuentra un formulario, cuenta con un inicio de sesion el caso es que si se abre una pestaña con el formulario y se comienzan a llenar los campos todo bien, pero si se abre otra pestaña en el mismo navegador, se inicia sesion de algun usuario se redirecciona a otra JSF de administracion para ese usuario y se cierra esa sesion afecta a la página que se abrió primero, hace que algunos datos se pierdan como si la pagina se hubiera abierto nuevamente, como hago para evitar esto?
Quizás te valga esto? https://coderwall.com/p/tjaxtq/jsf-multiple-tab-session-scoped-bean
Cecilio gracias por responder, se me olvidó comentar que el bean de la página JSF tiene un ámbito de ViewScoped y el parámetro en el web.xml STATE_SAVING_METHOD esta en client, aun con ese valor obtengo ese comportamiento.
no sabría decirte , porque en principio , parece correcto por lo que estas diciendo , pero puede haber algo que se escape , prueba con otro navegador si el tema se repite es casi seguro que hay q afinar algo
Buenas,
en mi equipo de desarrollo, hay una aplicación web que en GlasFish (3.1) no pierde la sesión, pero en JBoss (7) si.
¿Puedes darnos alguna pista al respecto?
Gracias!
Pues en principio asegurate de tener un jboss eap que son los oficiales , a veces los comunnity tienen problemas
Saludos.
Quería plantear la siguiente duda:
Tengo una aplicación web en la que pretendo evitar que varias personas puedan entrar con el mismo usuario y password.
¿Es posible de algún modo controlarlo mediante el uso de la sesión?
Gracias
pues en el session estar cargar el id del usuario en un variable a nivel de servlet context y comprobar en cada inicio de session
Hola se me plantea una duda. Imaginemos que un usuario A accede a un portal WEB mediante autenticación básica. Este usuario A puede navegar por toda la WEB gracias a su JSESSIONID. Ahora este usuario desea acceder a una subpágina requiere otra autenticación a través de CAS y ese JSESSIONID no le vale. ¿Esto es viable? ¿Se puede hacer con spring-security?O spring obviaría la necesidad de la segunda autenticación.
No lo he probado, te soy franco ,pero tiene pinta de tener que diseñar un custom provider en spring security o encadenar varios
Se que este blog ya tiene un par de años, soy estudiante de ciberseguridad, estoy en el modulo de la programación segura, analizando los ataques de session fixation, tienes algun blog dedicado a este ataque de sesion o un correo para contactarte.
me temo que no tengo nada escrito sobre este tema 🙁
[…] Cecilio Álvarez Caules. (2014). Usando Java Session en aplicaciones web. 9/12/2018, de arquitecturajava Sitio web: https://www.arquitecturajava.com/usando-java-session-en-aplicaciones-web/ […]
Muy bien aporte estimado Cecilio, tengo una duda con respecto a la session creada en una pestaña del navegador, es decir inicio sesion con el usuario 1 en una pestaña de mi navegador, luego abro otra pestaña y inicio sesion con el usuario 2, en eate momento la sesion del usuario 1 se cruza con la sesion del usuario 2 o siendo mas claro me parece que ambas pestañas del mismo navegador solo manejan una única sesion que es utilizada por ambas pestañas reemplazando los valores que hacen uso cada usuario. Por favor si me podrias brindar mayor detalle del… Read more »
en principio es la misma session porque comparten la misma cookie . Eso sí andate con ojo porque si desde dos pestañas se hacen peticiones ajax para actualizar la session . La session no esta protegida para situaciones asíncronas
Buenas amigo, tengo el mismo problema que varios te han comentado aquí. Te cuento, inicio sesión en 1 pestaña de una navegador, trato de iniciar sesión en otra pestaña del mismo navegador con otro usuario y cómo explicas, la sesión es la misma para ambos usuarios por el tema de la cookie y El navegador. Entonces, la 2da sesión me está sobreescribiendo los datos de la 1era sesión, ese es el problema, cómo hago para que esto no suceda? Ya que la 1era sesión es la que logra logearse, pero con los datos de la 2da sesión que es otro… Read more »
Sincroniza los bloques de código que accedan a la session
Lo que preguntas tiene que ver con como administra las cookies el navegedor. ( las cookies tienen relacion directa con la session )
Los navegadores mantienen las cookies asociadas a IPs a las que se conecta. En este caso en la misma IP por tanto es la misma cookie.
Si entraras desde otro navegador, entonces no sera la misma cookie.
Que tal hombre como estas? te comento tengo una session en el servidor y en el navegador(chrome) y al importar la cookies y ponerla en otro navegador(Opera) puedo navegar como si hubiera iniciado session en el segundo navegador.
claro , recuerda q la cookie de session se le puede asignar un tiempo de timeout, pero en principio si la tienes y es valida accedes
Hola Cecilio, en qué escenario utilizarías sessionStorage y HttpSession.
Es muy diferente , el httpsession se almacena en servidor mientras que el sessionStorage se almacena en el cliente. Cuando hablamos de un carrito de la compra. Usaría HttpSession en el servidor para mantener el carrito entre todas las páginas. En cambio usaría sessiónstorage para almacenar información de una app movil que tiene varias pantallas y los datos están muy ligados al cliente
Estimado Cecilio: mi consulta esta en parte relaciodana con el manejo de sesiones, logre implementar una aplicación web basada en primefaces y spring, autenticandome utilizando spring, lo que no se es donde realiza la verificación de la existencia de una sesion, es decir funciona pero en verdad no se como, estoy seguro de spring realiza la labor de alguna manera, deseo saber como realiza esto de manera de poder personalizar esa verificación y en caso de tener otra aplicación web esta reutilice la sesion ya creada por la otra aplicación. @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String name… Read more »
Spring Security usa una cadena de filtros , uno de ellos se encarga de la sessión . Echa un vistazo a https://docs.spring.io/spring-security/site/docs/3.0.x/reference/security-filter-chain.html
Buenas tardes Cecilio:
Me podría orientar sobre como mantener sesiónes activas tal y como se hacen con un explorador web y un servidor apache, pero yo lo quiero hacer desde una aplicación de escritorio java swing a un servidor apache. Desde su experiencia, necesito me facilite alguna clase que pueda utilizar o una libreria para mantener la sesión activa durante un cierto tiempo o mientras este abierta la aplicación de escritorio. De antemano muchas gracias
Esto normalmente se aborda con Statefull Session Beans , Se necesita un servidor full stack como JBoss , WebLogic , WebSphere para llevarlo a cabo.
hola me puedesayudar
cual es la pregunta? 🙂
Hola Que tal? Disculpa yo tengo que hacer algo semejante y la aplicación web esta realizada con spring y jsf, me podrias orientar como hacerlo?
Bajate mi libro del blog y te ayudará viene como hacerlo paso a paso 🙂
amigo jsf ya paso a la historia te sugiero que utilices sprint con Mybatis
Cuando una tecnología es un standard , sigue teniendo su hueco, primefaces es un ejemplo 😉
He visto un montón de preguntas en varios foros sobre un caso que ocurre diariamente en programación J2EE y nadie responde creo que aquí en este mundo todos nos copiamos de todos y nadie experimente por si mismo y lo que nadie inventa nadie lo sabe…. Mi pregunta es muy sencilla… Haces login en una JSP, se hace el submit hacia un sevlelt , este servlet crea una session … HttpSession sesion = request.getSession(); el sevlet hace un response.sendRedirect(“loginExito.jsp”) antes del response he creado un…. sesion.setAttribute(“usuario”, usu); una vez que estoy en loginExito.jsp…pinto…. hola usu “ESTAS VALIDADO” bien… hasta aqui… Read more »
Pues no he tenido tiempo de probarlo , pero parece que puede ser algún tema muy particular de como el navegador abre una nueva pestaña. Has probado a utilizar url rewriting y adjuntar a la pestaña que se abre el jsessionid?
Pudiste ver cuál es el tema?
Buenos días estimado Cecilio tengo una duda… con respecto al 2do servlet tienes la línea: HttpSession misession= (HttpSession) request.getSession(); para llamar a la sesión presente… pero si esta no existe… prácticamente se crearía una nueva sesión verdad… Entonces el hecho de usar apps web en línea no se trata netamente de trabajar con una única sesión para todo el trayecto del aplicativo??? de esta manera… dicha línea no sería: HttpSession misession= (HttpSession) request.getSession(false); cosa que si por algún motivo… me distraigo y pasan los 30min reglamentarios de sesión cuando regrese esto me daría error haciendo que no se vea dicha… Read more »
Si , eso esta claro , si ya no tienes sessión tienes que hacer algo para solventarlo. una opción es esta filtro invalidar session . Eres tu el que me ha preguntado por twitter verdad? 🙂
Hola,muy buena la explicación. Ahora bien, es necesario trabajar con sesiones en una aplicacón web? o se puede obviar?. Tengo una aplicación que tendrían que acceder alrededor de 13 personas para ingresar, modificar o eliminar datos a una base de datos mysql y lo estoy haciendo con jsp, servlet y accesos a bbdd. Muchas gracias
Sino necesitas que entre diversas vistas se comparta estado , entonces no las necesitas
En este momento estoy teniendo un Problema en el cual usuario con sesiones unicas al loguearse son redirigidos hacia sesiones que no son las suyas, el servidor de aplicaciones es GlassFish y el desarrollo esta en JSF, podrian indiacrme que pasos seguir para solucionar este inconveniente…
Gracias.
Pues eso suena bastante raro , da la sensación de que alguien no ha implementado bien las sessiones y el estado a nivel de programacion ,crea un objeto en session sencillo en una página y compruebalo
Hola Cecilio
Me gustaria saber como se manejar el paso de sesión entre aplicaciones web, para que una aplicacion A con usuario autenticado pueda invocar un servlet en la aplicacion B en la cual no tiene una sesion.
No se puede, cada aplicación tiene su sessión personal . No la puedes pasar entre aplicaciones. Hay formas extrañas de hacer algo parecido
Buenas y feliz año.
Trabajo en el mundo del testing y no son pocas las veces que me he encontrado problemas de desbordamiento de la memoria Java a causa del uso indiscriminado de la sesión de usuario (en pruebas de carga), por lo que +1 a no abusar del almacenamiento en sesión.
Mi comentario va más relacionado con la monitorización de recursos. ¿Conoces alguna herramienta que calcule el tamaño de la sesión de usuario?. Suelo utilizar JavaMelody para estos casos, pero por si conocieras otra.
Gracias, saludos.
Pues no conozco , no estoy tan metido en el mundo de las pruebas de carga 🙂 , pero muchas gracias por el aporte de Java Melody lo echaré un veo. Feliz Año 😉
Hola y gracias por el ejemplo. He utilizado picket link para manejar los inicios de sesión, ¿consideras este framework robusto?, ¿cual es tu opinión al respecto de esta librería ?.
Saludos
No la conozco 🙂 , pero la voy a echar un veo gracias por el aporte 😉
Veo que esta creada por redhat … seguro que es una buena opcion 🙂
Hola amigo, en base a este ejemplo, yo necesito manejar simplemente una variable. La cosa es asi, tengo un jsp que envía los datos al servlet y este se encarga de realizar el Insert, a su ves este servlet debe redirigir a otra pagina(estadisticas.jsp) y mostrar un mensaje de exito(que los datos se cargaron correctamente) y si la carga no se realizo correctamente debe mandar a otra pagina(index.jsp) y mostrar también un mensaje. Mi idea era manejar una variable session(que seria un booleano) en el servlet y dependiedo si cargaron bien los datos se ponga en true y sino que… Read more »
Podrías hacerlo con sessiones pero no es obligatorio que ya se lo podrías pasar a los despachadores vía setAttribute en la request. Las sessiones se usan más cuando muchas páginas comparten la información
Buena tarde tengo una duda que me recomiendas utilizar para una aplicación desarrollada con java ee que utiliza cliente/servidor, en el servidor cree un webservice pero no tengo bien claro si usar Stateless o Stateful, el cliente estará en swing.
Los webservices normalmente no almacenan estado y son stateless
Cecilio, gracias por tus aportes, aunque con una duda respecto a los ejemplos que expones con la constante:
private static final long serialVersionUID = 1L;
Me he percatado que asignas el mismo serialVersionUID para estas clases, tanto para esta entrada en tu blog como en otros ejemplos de otras entradas (soy fiel seguidor). Me da la impresión que al tratarse de un UID tendría que ser univoco, y del no ser así, ¿que sentido tiene informar un mismo valor por defecto?
Y nuevamente gracias por tu dedicación.
Mientras todas tengan el mismo número no genera problema , este campo se usa cuando hablamos de programación distribuida y una clase está ubicada en dos máquinas diferentes
Cecilio, aprovechando tu disposición, como haces para modificar el tiempo por defecto de las sesiones del web.xml, si al momento de crear un servlet prefieres trabajar con anotaciones.?
gracias
el web.xml sigue siendo necesario para algunas tareas , el tiempo de timeout se configura en él 🙂
Que tal muchas gracias por compartir tu conocimiento.
Yo tengo una aplicacion web y las sesiones entre usuarios no se mezclan, pero cuando un usuario edita un registro, y luego abre otra pestaña y edita otro registro este ultimo sobre escribe el primer registro, este ejemplo cubre este escenaro?
Es normal las dos pestañas comparten la misma sessión
Hola Cecilio, Ante todo, gracias por compartir. ¿Desde tu conocimiento, consideras el servidor OC4J como de Producción?. En este servidor se me ha dado el caso de mezcla de sesiones entre usuarios. La particularidad es que la aplicación en sí esta integrada por varios módulos web (.war), y es desde cualquiera de estos módulos que se puede hacer el login (momento de creación de la sesión)… ¿Puede ser esta la causa? Me refiero a que quizás cada módulo web controla la unicidad en los identificadores de sesión, ¿pero casualmente un identificador de sesión podría verse repetido en otro módulo?. El… Read more »
En principio no debiera dar problemas ya que todos los servidores pasan un proceso de certificacion, pero oC4j ya es bastante antiguo.
Estoy haciendo una pagina web donde ocupo iniciar session, en index tengo el formulario para el login, en otro jsp tengo la pagina que seria mostrado despues de pasar por login, pero si ingreso la url directa de dicha pagina sin pasar por login, puedo ingresar, como se puede controlar esto??
Tienes que gestionar la seguridad https://www.arquitecturajava.com/seguridad-y-jaas/
[…] artículos relacionados : El concepto de HttpSession , Manejando […]
“…este protocolo es stateless (sin estado).” Precisamente lo del estado no lo he entendido muy bien. Qué implica tener o no tener estado?
El estado implica que una variable mantiene su valor entre varias páginas .Estos datos se almacenan en session normalmente.
Entonces los managedBeans son EJB @Statefull? (por ejemplo)
No pero si tienen scope de sesión mantienen estado
Cecilio gracias por compartir. Con respeto a la Session yo tengo una mala experiencia, tengo una sistema que sirve para los usuarios vean sus estados de cuenta bancarias. Y una vez me paso que se “mezclaron las sessiones” y un usuario pudo ver las cuentas del otro. Me causo muchos problemas como haz de imaginar. Es algo no encontré explicación, tanto que leí en algun foto de Glassfish, que era un issue que tenia el mismo GF. Esto me hizo meter un control extra para validar la Session y cuando pasará eso de nuevo detectarlo y sacar al usuario para… Read more »
GlassFish siempre ha sido un servidor para probar las especificaciones no tanto un servidor puro de producción tipo Tomcat/WebLogic/JBoss/Websphere 🙁 . Probablemente ese era tu mayor problema
Hola, yo tuve un problema similar pero en php cree un sistema de login sencillo para hacer una encuesta, basicamente un formulario con algunas preguntas… Cuando ingresaban más de 15 usuarios las sesiones se cruzaban y aparecían datos de otro usuario, nunca supe porque, no hay info al respecto, ahora voy a hacer la misma app usando JEE y me dices que tiene el mismo problema me preocupa, si tienes más info al respecto me podrías ayudar, te dejo mi correo zirtrex@live.com
No debieras tener ningún problema con las sessiones ya que asignan una cookie al navegador que te identifica de forma única
Grandisimo ejemplo! Gracias por compartir…
Pero a raiz de el comentario de arriba y como tu tambien dices, si no se puede abusar del uso de la sesión, ¿que alternativas tenemos? ¿Como podemos hacer esto de otra manera?
gracias! un saludo
Cada framework web tiene las suyas. Por ejemplo JSF tiene pageFlows y conversaciones y Spring MVC webflows
¡Buen ejemplo! Aunque es una práctica peligrosa, lástima que pocos cumplan esto: “no se debe abusar del almacenamiento de objetos en Session”.
gracias 🙂