O desenvolvimento de um sistema de login robusto em aplicações Java Web envolve a segregação de responsabilidades entre as camadas de persistência, lógica de negócio e controle. Abaixo, detalhamos o fluxo de implementação de um mecanismo de autenticação utilizando o padrão MVC clássico.
1. Camada de Acesso a Dados (DAO)
A primeira etapa consiste em criar um método capaz de extrair as informações do usuário do banco de dados com base em um identificador único. Esta camada interage diretamente com o banco através de JDBC.
public User findUserByIdentifier(Connection conn, String loginName) throws SQLException {
PreparedStatement stmt = null;
ResultSet resultSet = null;
User account = null;
if (conn != null) {
String query = "SELECT * FROM sys_user WHERE login_id = ?";
stmt = conn.prepareStatement(query);
stmt.setString(1, loginName);
resultSet = stmt.executeQuery();
if (resultSet.next()) {
account = new User();
account.setInternalId(resultSet.getInt("id"));
account.setLoginId(resultSet.getString("login_id"));
account.setFullName(resultSet.getString("full_name"));
account.setHashedPassword(resultSet.getString("password_hash"));
account.setRoleLevel(resultSet.getInt("role_id"));
// Atribuição de outros campos necessários...
}
// Fechamento seletivo de recursos para manter a conexão ativa para a Service
if (stmt != null) stmt.close();
if (resultSet != null) resultSet.close();
}
return account;
}
2. Camada de Lógica de Negócio (Service)
A classe de serviço gerencia a transação e valida se as credenciais fornecidas pelo usuário coincidem com os dados armazenados.
public class AccountService {
private UserDAO persistenceLayer = new UserDAOImpl();
public User authenticate(String loginId, String plainPassword) {
Connection dbConn = null;
User activeUser = null;
try {
dbConn = DatabaseUtility.getConnection();
activeUser = persistenceLayer.findUserByIdentifier(dbConn, loginId);
} catch (Exception error) {
error.printStackTrace();
} finally {
DatabaseUtility.releaseResources(dbConn, null, null);
}
// Validação da senha
if (activeUser != null && !activeUser.getHashedPassword().equals(plainPassword)) {
activeUser = null;
}
return activeUser;
}
}
3. Controlador de Autenticação (Servlet)
O Servlet atua como o orquestrador, recebendo a requisição HTTP, invocando o serviço e decidindo qual será a próxima view apresentada ao cliente.
public class AuthServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String identifier = request.getParameter("loginField");
String secretKey = request.getParameter("passwordField");
AccountService authService = new AccountService();
User sessionUser = authService.authenticate(identifier, secretKey);
if (sessionUser != null) {
// Sucesso: Armazena o objeto na sessão e redireciona
request.getSession().setAttribute("LOGGED_USER", sessionUser);
response.sendRedirect(request.getContextPath() + "/dashboard/home.jsp");
} else {
// Falha: Retorna ao login com mensagem de erro via encaminhamento (forward)
request.setAttribute("errorMessage", "Credenciais Inválidas!");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
}
4. Encerramento de Sessão (Logout)
Para garantir a segurança, é necessário invalidar a sessão do servidor quando o usuário desejar sair do sistema.
public class TerminateSessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession currentSession = req.getSession(false);
if (currentSession != null) {
currentSession.removeAttribute("LOGGED_USER");
currentSession.invalidate();
}
resp.sendRedirect(req.getContextPath() + "/login.jsp");
}
}
5. Filtro de Segurança (Acesso Restrito)
Um Filter entercepta as requisições para páginas protegidas, verificando se existe um usuário autenticado na sessão ativa.
public class SecurityFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) req;
HttpServletResponse httpResponse = (HttpServletResponse) res;
Object userToken = httpRequest.getSession().getAttribute("LOGGED_USER");
if (userToken == null) {
// Acesso não autorizado: Redireciona para página de erro ou login
httpResponse.sendRedirect(httpRequest.getContextPath() + "/unauthorized.jsp");
} else {
// Prossegue com a requisição
chain.doFilter(req, res);
}
}
}
6. Configuração no Web Descriptor (web.xml)
Para que os componentes funcionem, as rotas devem ser devidamente mapeadas no arquivo de configuração da aplicação.
<!-- Mapeamento do Servlet de Login -->
<servlet>
<servlet-name>AuthServlet</servlet-name>
<servlet-class>com.app.controller.AuthServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AuthServlet</servlet-name>
<url-pattern>/doAuth.action</url-pattern>
</servlet-mapping>
<!-- Configuração do Filtro de Proteção -->
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>com.app.filter.SecurityFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>/dashboard/*</url-pattern>
</filter-mapping>