Gerenciamento de Sessão em Aplicações Web Servlet Java é um tópico muito interessante. As sessões em Servlets Java são gerenciadas de várias maneiras, como Cookies, API HttpSession, reescrita de URL, etc. Este é o terceiro artigo na série de tutoriais de Aplicações Web em Java, você pode querer verificar os dois artigos anteriores também.
Gerenciamento de Sessão em Java
Este artigo tem como objetivo explicar sobre o gerenciamento de sessões em servlets usando diferentes técnicas e exemplos de programas.
-
O que é uma Sessão?
O protocolo HTTP e os Servidores Web são stateless, o que significa que para o servidor web cada requisição é uma nova requisição a ser processada e eles não conseguem identificar se está vindo de um cliente que enviou requisições anteriormente. Mas às vezes em aplicações web, precisamos saber quem é o cliente e processar a requisição de acordo. Por exemplo, uma aplicação de carrinho de compras deve saber quem está enviando a requisição para adicionar um item e em qual carrinho o item deve ser adicionado, ou quem está enviando a requisição de checkout para que possa cobrar o valor do cliente correto. A sessão é um estado de conversação entre cliente e servidor e pode consistir em várias requisições e respostas entre cliente e servidor. Como tanto o HTTP quanto o Servidor Web são stateless, a única maneira de manter uma sessão é quando alguma informação única sobre a sessão (ID da sessão) é passada entre servidor e cliente em cada requisição e resposta. Existem várias maneiras de fornecer um identificador único na requisição e na resposta.
-
Autenticação de Usuário – Esta é a maneira mais comum em que o usuário pode fornecer credenciais de autenticação na página de login e então podemos passar as informações de autenticação entre o servidor e o cliente para manter a sessão. Este método não é muito eficaz porque não funcionará se o mesmo usuário estiver logado em navegadores diferentes.
-
Campo Oculto HTML – Podemos criar um campo oculto único no HTML e quando o usuário começa a navegar, podemos definir seu valor único para o usuário e acompanhar a sessão. Este método não pode ser usado com links porque precisa que o formulário seja enviado toda vez que a requisição é feita do cliente para o servidor com o campo oculto. Além disso, não é seguro porque podemos obter o valor do campo oculto a partir do código-fonte HTML e usá-lo para hackear a sessão.
-
Redefinição de URL – Podemos anexar um parâmetro de identificação de sessão com cada requisição e resposta para acompanhar a sessão. Isso é muito tedioso porque precisamos acompanhar esse parâmetro em todas as respostas e garantir que não esteja entrando em conflito com outros parâmetros.
-
Cookies – Cookies são pequenas informações enviadas pelo servidor web no cabeçalho da resposta e são armazenadas nos cookies do navegador. Quando o cliente faz uma nova requisição, adiciona o cookie ao cabeçalho da requisição e podemos utilizá-lo para acompanhar a sessão. Podemos manter uma sessão com cookies, mas se o cliente desabilitar os cookies, isso não funcionará.
-
API de Gerenciamento de Sessão – A API de Gerenciamento de Sessão é construída sobre os métodos acima para rastreamento de sessão. Algumas das principais desvantagens de todos os métodos acima são:
- Muitas vezes, não queremos apenas rastrear a sessão, precisamos armazenar alguns dados na sessão que podemos usar em futuras requisições. Isso exigirá muito esforço se tentarmos implementar isso.
- Todos os métodos acima não são completos por si só, todos eles não funcionarão em um cenário particular. Portanto, precisamos de uma solução que possa utilizar esses métodos de rastreamento de sessão para fornecer gerenciamento de sessão em todos os casos.
É por isso que precisamos da API de Gerenciamento de Sessão e a tecnologia de Servlet J2EE vem com uma API de gerenciamento de sessão que podemos usar.
-
- html
Gerenciamento de Sessão em Java – Cookies
Os cookies são muito utilizados em aplicações web para personalizar a resposta com base em suas escolhas ou para acompanhar a sessão. Antes de avançarmos para a API de Gerenciamento de Sessão do Servlet, gostaria de mostrar como podemos acompanhar a sessão com cookies por meio de uma pequena aplicação web. Criaremos uma aplicação web dinâmica ServletCookieExample com a estrutura do projeto como na imagem abaixo.
O descritor de implantação web.xml da aplicação web é:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ServletCookieExample</display-name> <welcome-file-list> <welcome-file>login.html</welcome-file> </welcome-file-list> </web-app>
A página inicial de nossa aplicação é login.html, onde obteremos os detalhes de autenticação do usuário.
<!DOCTYPE html> <html> <head> <meta charset="US-ASCII"> <title>Página de Login</title> </head> <body> <form action="LoginServlet" method="post"> Nome de usuário: <input type="text" name="user"> <br> Senha: <input type="password" name="pwd"> <br> <input type="submit" value="Login"> </form> </body> </html>
Aqui está o LoginServlet que cuida da solicitação de login.
pacote com.journaldev.servlet.session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Implementação do Servlet da Classe Login */ @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final String userID = "Pankaj"; private final String password = "journaldev"; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // obter parâmetros de solicitação para userID e senha String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); if(userID.equals(user) && password.equals(pwd)){ Cookie loginCookie = new Cookie("user",user); // definindo cookie para expirar em 30 minutos loginCookie.setMaxAge(30*60); response.addCookie(loginCookie); response.sendRedirect("LoginSuccess.jsp"); }else{ RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html"); PrintWriter out= response.getWriter(); out.println("<font color=red>Nome de usuário ou senha incorretos.</font>"); rd.include(request, response); } } }
Observe o cookie que estamos definindo na resposta e depois encaminhando para LoginSuccess.jsp, este cookie será usado lá para rastrear a sessão. Observe também que o tempo limite do cookie é definido para 30 minutos. Idealmente, deveria haver uma lógica complexa para definir o valor do cookie para rastreamento de sessão, de modo que não entre em conflito com qualquer outra solicitação.
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>Página de Sucesso do Login</title> </head> <body> <% String userName = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); } } if(userName == null) response.sendRedirect("login.html"); %> <h3>Olá <%=userName %>, login bem-sucedido.</h3> <br> <form action="LogoutServlet" method="post"> <input type="submit" value="Logout" > </form> </body> </html>
Observe que se tentarmos acessar o JSP diretamente, seremos encaminhados para a página de login. Quando clicarmos no botão de Logout, devemos garantir que o cookie seja removido do navegador do cliente.
pacote com.journaldev.servlet.session; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Implementação do Servlet da Classe Logout */ @WebServlet("/LogoutServlet") public class LogoutServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); Cookie loginCookie = null; Cookie[] cookies = request.getCookies(); if(cookies != null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")){ loginCookie = cookie; break; } } } if(loginCookie != null){ loginCookie.setMaxAge(0); response.addCookie(loginCookie); } response.sendRedirect("login.html"); } }
N
-
Sessão em Java Servlet – HttpSession
A API Servlet fornece gerenciamento de sessão através da interface
HttpSession
. Podemos obter a sessão a partir do objeto HttpServletRequest usando os seguintes métodos. HttpSession nos permite definir objetos como atributos que podem ser recuperados em solicitações futuras.- HttpSession getSession() – Este método sempre retorna um objeto HttpSession. Ele retorna o objeto de sessão associado à solicitação. Se a solicitação não tiver uma sessão associada, então cria uma nova sessão e a retorna.
- HttpSession getSession(boolean flag) – Este método retorna um objeto HttpSession se a solicitação tiver uma sessão, caso contrário, retorna null.
Alguns dos métodos importantes de HttpSession são:
- String getId() – Retorna uma string contendo o identificador único atribuído a esta sessão.
- Object getAttribute(String name) – Retorna o objeto vinculado ao nome especificado nesta sessão, ou null se nenhum objeto estiver vinculado ao nome. Alguns outros métodos para trabalhar com atributos de sessão são
getAttributeNames()
,removeAttribute(String name)
esetAttribute(String name, Object value)
. - long getCreationTime() – Retorna o momento em que esta sessão foi criada, medido em milissegundos desde a meia-noite de 1º de janeiro de 1970 GMT. Podemos obter o último tempo de acesso com o método
getLastAccessedTime()
. - setMaxInactiveInterval(int interval) – Especifica o tempo, em segundos, entre as solicitações do cliente antes que o contêiner do servlet invalide esta sessão. Podemos obter o valor do tempo limite da sessão do método
getMaxInactiveInterval()
. - ServletContext getServletContext() – Retorna o objeto ServletContext para a aplicação.
- boolean isNew() – Retorna true se o cliente ainda não conhecer a sessão ou se o cliente optar por não participar da sessão.
- void invalidate() – Invalida esta sessão e desvincula quaisquer objetos vinculados a ela.
Entendendo o Cookie JSESSIONID
Ao usarmos o método HttpServletRequest getSession() e ele cria uma nova solicitação, ele cria o novo objeto HttpSession e também adiciona um Cookie ao objeto de resposta com o nome JSESSIONID e o valor como ID de sessão. Esse cookie é usado para identificar o objeto HttpSession em solicitações futuras do cliente. Se os cookies estiverem desativados no lado do cliente e estivermos usando a reescrita de URL, então este método usa o valor jsessionid da URL da solicitação para encontrar a sessão correspondente. O cookie JSESSIONID é usado para rastreamento de sessão, então não devemos usá-lo para nossos propósitos de aplicativo para evitar quaisquer problemas relacionados à sessão. Vamos ver um exemplo de gerenciamento de sessão usando o objeto HttpSession. Vamos criar um projeto web dinâmico no Eclipse com o contexto do servlet como ServletHttpSessionExample. A estrutura do projeto será semelhante à imagem abaixo.
login.html é o mesmo que o exemplo anterior e definido como página de boas-vindas para a aplicação em web.xml O servlet LoginServlet irá criar a sessão e definir atributos que podemos usar em outros recursos ou em solicitações futuras.
package com.journaldev.servlet.session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class LoginServlet */ @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final String userID = "admin"; private final String password = "password"; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // get request parameters for userID and password String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); if(userID.equals(user) && password.equals(pwd)){ HttpSession session = request.getSession(); session.setAttribute("user", "Pankaj"); //setting session to expiry in 30 mins session.setMaxInactiveInterval(30*60); Cookie userName = new Cookie("user", user); userName.setMaxAge(30*60); response.addCookie(userName); response.sendRedirect("LoginSuccess.jsp"); }else{ RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html"); PrintWriter out= response.getWriter(); out.println("<font color=red>Either user name or password is wrong.</font>"); rd.include(request, response); } } }
Nosso código LoginSuccess.jsp é dado abaixo.
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Página de Sucesso no Login</title>
</head>
<body>
<%
//permitir acesso apenas se a sessão existir
String user = null;
if(session.getAttribute("user") == null){
response.sendRedirect("login.html");
}else user = (String) session.getAttribute("user");
String userName = null;
String sessionID = null;
Cookie[] cookies = request.getCookies(); -
Gerenciamento de Sessão em Java Servlet – Reescrita de URL
Como vimos na última seção, podemos gerenciar uma sessão com HttpSession, mas se desativarmos os cookies no navegador, não funcionará porque o servidor não receberá o cookie JSESSIONID do cliente. A API Servlet fornece suporte para reescrita de URL que podemos usar para gerenciar a sessão nesse caso. A melhor parte é que, do ponto de vista da codificação, é muito fácil de usar e envolve apenas um passo – codificar a URL. Outra coisa boa com a Codificação de URL Servlet é que é uma abordagem de fallback e só entra em ação se os cookies do navegador estiverem desativados. Podemos codificar a URL com o método
encodeURL()
de HttpServletResponse e se precisarmos redirecionar a solicitação para outro recurso e quisermos fornecer informações de sessão, podemos usar o métodoencodeRedirectURL()
. Criaremos um projeto semelhante ao acima, exceto que usaremos métodos de reescrita de URL para garantir que o gerenciamento de sessão funcione corretamente mesmo se os cookies estiverem desativados no navegador. A estrutura do projeto ServletSessionURLRewriting no eclipse parece com a imagem abaixo.pacote com.journaldev.servlet.session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Implementação do Servlet da classe LoginServlet */ @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final String userID = "admin"; private final String password = "password"; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // obter parâmetros de solicitação para userID e senha String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); if(userID.equals(user) && password.equals(pwd)){ HttpSession session = request.getSession(); session.setAttribute("user", "Pankaj"); // definindo a sessão para expirar em 30 minutos session.setMaxInactiveInterval(30*60); Cookie userName = new Cookie("user", user); response.addCookie(userName); // Obter a string de URL codificada String encodedURL = response.encodeRedirectURL("LoginSuccess.jsp"); response.sendRedirect(encodedURL); }else{ RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html"); PrintWriter out= response.getWriter(); out.println("<font color=red>Nome de usuário ou senha incorretos.</font>"); rd.include(request, response); } } }
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>Página de Sucesso no Login</title> </head> <body> <% // permitir acesso apenas se a sessão existir String user = null; if(session.getAttribute("user") == null){ response.sendRedirect("login.html"); }else user = (String) session.getAttribute("user"); String userName = null; String sessionID = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue(); } }else{ sessionID = session.getId(); } %> <h3>Oi <%=userName %>, login bem-sucedido. Seu ID de Sessão=<%=sessionID %></h3> <br> Usuário=<%=user %> <br> <!-- precisamos codificar todas as URLs onde queremos que as informações da sessão sejam passadas --> <a href="<%=response.encodeURL("CheckoutPage.jsp") %>">Página de Checkout</a> <form action="<%=response.encodeURL("LogoutServlet") %>" method="post"> <input type="submit" value="Logout" > </form> </body> </html>
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>Página de Sucesso no Login</title> </head> <body> <% String userName = null; // permitir acesso apenas se a sessão existir if(session.getAttribute("user") == null){ response.sendRedirect("login.html"); }else userName = (String) session.getAttribute("user"); String sessionID = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); } } %> <h3>Oi <%=userName %>, faça o checkout.</h3> <br> <form action="<%=response.encodeURL("LogoutServlet") %>" method="post"> <input type="submit" value="Logout" > </form> </body> </html>
pacote com.journaldev.servlet.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/**
* Implementação do Servlet da classe LogoutServlet
*/
@WebServlet("/LogoutServlet")
public
Isso é tudo para o gerenciamento de sessões em servlets Java, vamos analisar Filtros e Ouvintes de Servlet e Cookies em artigos futuros. Atualização: Confira o próximo artigo na série Filtro de Servlet.