Servlet de Login

Boa tarde,

Estou com algumas dúvidas e gostaria das dicas de vocês para fazer um bom servlet para autenticar meus usuários no sistema.

Primeiro alguns pré-requisitos

  • Precisa ser em MVC
  • O sistema tem telas especificas para Administradores e Usuários, ou seja, conforme sua permissão ele abre as paginas X ou Y
  • Os usuários, senhas e nível de acesso (Administrador/Usuário) já estão cadastrados no banco de dados.

O que eu já fiz:

  • Criei a JSP, onde o forma chama o Servlet (doPost)
  • Criei uma classe chamada Login que gera um objeto com usuario e senha
  • Criei uma classe pra conexão com o banco de dados (MySQL - funcionando)
  • Criei a classe DAO que faz um select no banco e pega as informacoes do usuário digitado
  • Criei o servlet que instancia o objeto Login e passa esse objeto para a classe DAO que pesquisa no banco.

Minha dúvida é…

Preciso que a classe DAO retorne pro servlet se o usuário é ou não válido e também preciso dizer se esse usuário é ou não administrador do sistema.

Depois disso preciso criar uma session pra guardar a informação do usuário e o nivel de permissão, que vão ser usados pra consultar mais tarde nas outras telas.
Como devo proceder?

JSP

<%@ page contentType="text/html; charset=utf-8" language="java" import="java.sql.*" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SGC - Sistema de Gerenciamento Condominial</title>
<style rel="stylesheet" type="text/css" />

html, body { padding: 0; margin: 0;}
p {padding: 0; margin: 0;}
#geral {width: 100%; height: 100%;}
#fundo {width: 100%; height: 200px; background-image: url(fundologin.png); position: absolute; top: 50%; margin-top: -100px;}
#logoform {width: 455px; height: 200px; margin: 0 auto;}
#logo {float:left; margin-top: 35px;}
#form {float:right; margin-top: 40px; font-family: Tahoma; font-size: 10px;}
#campo {border: 1px solid #CCC; height: 20px; width: 150px; margin-bottom: 5px; }
#botao {height: 25px; width: 150px; background: #FFF; margin-top: 8px; font-family:Tahoma;}

</style>
</head>

<body>
<div id="geral">
	<div id="fundo">
    	<div id="logoform">
            <img id="logo" src="logo248x130.png"/>
            <form id="form" method="post" action="Login">
            	<p>Usuário</p>
       		<p><input id="campo" name="usuario" type="text" /></p>
                <p>Senha</p>
            	<p><input id="campo" name="senha" type="password" /></p>
            	<p><input id="botao" name="entrar" type="submit" value="ENTRAR"/></p>
            </form>
        </div>
    </div>
</div>
</body>
</html>

Classe pra instanciar os Objetos de Login

package Object;


public class LoginObject {
   private String usuario;  
   private String senha;  
  
     
   public String getUsuario() {  
      return usuario;  
   }  
     
   public void setUsuario(String usuario) {  
      this.usuario = usuario;  
   }  
     
   public String getSenha() {  
      return senha;  
   }  
     
   public void setSenha(String senha) {  
      this.senha = senha;  
   }  
}

DAO que deveria retornar alguma coisa, por enquanto só ta fazendo uns println

package DAO;

import Conexao.Conexao;
import java.sql.Connection;
import java.sql.PreparedStatement;  
import java.sql.ResultSet;
import java.sql.SQLException; 
import Object.LoginObject;

/**
 *
 * @author murilo
 */
public class LoginDAO extends Conexao{

    public static void Login(LoginObject login) throws SQLException, ClassNotFoundException {  
        
        String sql = "SELECT * FROM condomino WHERE usuario=? AND senha=?";
        
        Connection con = GetConexao();  
        
        PreparedStatement psmt = con.prepareStatement(sql);
        
        psmt.setString(1, login.getUsuario());  
        psmt.setString(2, login.getSenha());
        
        ResultSet rs = psmt.executeQuery();
      
        if(rs.next()){
            System.out.println(rs.getString("usuario"));
            System.out.println(rs.getString("senha"));
            System.out.println(rs.getString("administrador"));
        } else {
            System.out.println("Nenhum usuario!");
        }
        psmt.close();
        rs.close();
        con.close();  
  
    }

}

Servlet que deveria receber o retorno da DAO e criar a session.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Servlet;

import java.io.IOException;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import Object.LoginObject;
import DAO.LoginDAO;

/**
 *
 * @author murilo
 */
public class LoginServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, SQLException, ClassNotFoundException {
        response.setContentType("text/html;charset=UTF-8");
        
        // joga usuario e senha nas strings
        String usuario = request.getParameter("usuario");
        String senha = request.getParameter("senha");
        
        // instancia o objeto login que vai ser usado na DAO
        LoginObject login = new LoginObject();
        login.setUsuario(usuario);
        login.setSenha(senha);
        
        // define a pagina de retorno como null
        String pagina = null;
        
        // chama a dao que verifica o login no banco e retorna se é administrador ou não
        LoginDAO.Login(login);
        
        response.setContentType("text/html;charset=UTF-8");
        
        if(usuario.equals("Admin") && senha.equals("teste")) {
            HttpSession sessao = request.getSession();
            sessao.setAttribute("login", usuario);
            sessao.setAttribute("permissao", "Admintrador");
            pagina = "Administrador/home.jsp";
            response.sendRedirect(pagina);
	}
        else if(usuario.equals("Usuario") && senha.equals("teste")) {
            HttpSession sessao = request.getSession();
            sessao.setAttribute("login", usuario);
            sessao.setAttribute("permissao", "Usuario");
            pagina = "Usuario/home.jsp";
            response.sendRedirect(pagina);
        }
        else {
            pagina = "index.jsp";
            response.sendRedirect(pagina);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (SQLException ex) {
            Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (SQLException ex) {
            Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Obrigado quem puder me dar umas dicas ae! =)

Oi!

Infelizmente faz muito tempo que não lido com Servlets dessa forma, usando-se JSP.
Não sei lhe afirmar como faria para controle de acesso do usuário a determinadas páginas, mas acredito que idéia seja de jogar na Sessão como está fazendo mesmo.
Para cada página é capturar o usuário da sessão e verificar se o logado tem ou não acesso aquela função.

Para algo mais legível, o ideal é que nem fosse habilitado determinadas funções do sistema para usuário comum, como por exemplo, cadastrar um apartamento (supondo que seja uma função exclusiva do administrador).

Sobre o seu DAO, bastaria modificar isso:

[code]public class LoginDAO extends Conexao{

public static boolean Login(LoginObject login) throws SQLException, ClassNotFoundException {     
       
    String sql = "SELECT * FROM condomino WHERE usuario=? AND senha=?";   
       
    Connection con = GetConexao();      
    try {          
    PreparedStatement psmt = con.prepareStatement(sql);   
       
    psmt.setString(1, login.getUsuario());     
    psmt.setString(2, login.getSenha());   
       
    ResultSet rs = psmt.executeQuery();   
     
    if(rs.next()){   
        return true;
    } else {   
        return false;        
    }   
    } finally {
    psmt.close();   
    rs.close();   
    con.close();     
   }
}   

} [/code]

Perceba que adicionei um bloco try-finally ao seu código. Isso obriga que o seu método vai sempre executar os close, no PreparedStatement, ResultSet e no Connection.
Só mais dois detalhes sobre isso:

1 - Verifique no finally se as variavéis não são nulas, podem ser caso ocorra exceção.
2 - Faça o tratamento com try-cath das exceções, ou deseja que elas sejam jogadas “para cima” e caim lá na sua página JSP sem tratamento algum? Fica feio aparecer ao usuário algo como “SQLException: bla bla bla” não acha? :slight_smile:

Abraços.

Oi!

Infelizmente sobre a questão de como tratar o acesso as paginas no JSP com Servlets não poderia ajudar muito, trabalhei com Struts e JSP mas faz bastante tempo (praticamente 2 anos), então não me recordo como na época eu tratava essa situação. Mas nada que uma pesquisa pela net não resolva.
Creio que usar a sessão para saber o usário faz todo sentido e seja o caminho correto, só para ficar algo mais “bonito” e “legível” você pode nem sequer mostrar ao usuário comum páginas restritas, somente quando o usuário for de nível administrador tais páginas devam ser exibidas.

No JSF isso pode ser feito com um <f:subview rendered=“true”> da vida, em JSP teria de dar uma olhada.
Sobre o seu select referente ao usário, eu modificaria o seguinte:

[code] public static boolean Login(LoginObject login) throws SQLException, ClassNotFoundException {

    String sql = "SELECT * FROM condomino WHERE usuario=? AND senha=?";   
       
    Connection con = GetConexao();     
    try {
    PreparedStatement psmt = con.prepareStatement(sql);   
       
    psmt.setString(1, login.getUsuario());     
    psmt.setString(2, login.getSenha());   
       
    ResultSet rs = psmt.executeQuery();   
     
    if(rs.next()){   
       return true;
    } else {   
       return false;
    }
    } finally {   
    psmt.close();   
    rs.close();   
    con.close();     
    }
 
}   

} [/code]

Perceba três detalhes:

1 - Alterei o retorno para booleano. Caso ele cai no rs.next() signifca que encontrou o registro, portanto, usuário existe, caso contrário, é false.

2 - Adicionei um bloco finally, isso é muito importante para sempre fechar os PreparedStatement, ResultSet e Connection, de modo a não ter problemas com o Pool. Dependendo do container web que utilizar, podes até configurar o mesmo para gerenciar isso para você. Só um detalhe muito importante, verifique se as variavéis não são nulas dentro do finally antes de executar o close, ok?

3 - Use um bloco try-cath no seu método, caso contrário, vai “lançar para cima” as possíveis exceções e cair em sua página JSP. Fica feio aparecer ao usuário “SQLException: bla bla bla” certo?

Forte abraço.

O problema é que essa pesquisa q vc fez só serve pra validar se o usuário existe ou não…

ainda sim preciso validar se é ou não administrador.

Posso por no return uma variavel?

por exemplo

String permissao = null;

se ele for administrador

permissao = “admin”;

se ele for usuario

permissao = “usuario”;

se ele nao for nenhum dos dois

permissao = “erro”;

Dai eu trato esses retornos no servlet…

edit:

as paginas q ele nao tem permissão nem mostra q existem pra ele…
mais se por ventura ele digitar o caminho no browser…
não existe nada que valide pra dizer q ele não tem acesso…

Oi!

Interessante.
Se você tem a variavél no seu Banco de dados que indica o nível do usuário, é bem simples.
Vamos usar OO e Java, que tal? Crie um Enumeration e deixa que ele faça o controle para você.

Podes fazer algo assim:

[code] enum Login {
ADMINISTRADOR (1, “Administrador”),

	NORMAL_USER (2, "Usuario"),

                            UNIDENTIFIED (3, "Não Identificado");
	
	private Login(int code, String description) {
		this.code = code;
		this.description = description;
	}
	
	private int code;
	private String description;
	
	public static Login getLoginByCode(int code) {
		for(Login login : Login.values()) {
			if(login.getCode() == code) {
				return login;
			}
		}
		throw new IllegalArgumentException(code + " is not valid!");
	}
	
	public static Login getLoginByDescription(String description) {
		for(Login login : Login.values()) {
			if(login.getDescription().equalsIgnoreCase(description)) {
				return login;
			}
		}
		throw new IllegalArgumentException(description + " is not valid!");
	}
	
	public int getCode() {
		return code;
	}
	public void setCode(int code) {
		this.code = code;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}		
}[/code]

Se você guarda como um código, que eu acho mais fácil do que uma String, para que tu não tenha problemas com acentuação, por exemplo, podes fazer isso:

if(rs.next()) { int code = rs.getInt("administrador"); return Login.getLoginByCode(code); } else { return Login.UNIDENTIFIED; }

Agora basta lançar um Switch no seu Servlet que fica fácil de saber quem está logado.
Abraços.

P.s: ainda dá de usar Polimorfismo, se achar interessante, podes estudar uma maneira de fazer isso. Senão, o switch resolve facilmente.

[quote=dombeck]
edit:

as paginas q ele nao tem permissão nem mostra q existem pra ele…
mais se por ventura ele digitar o caminho no browser…
não existe nada que valide pra dizer q ele não tem acesso…[/quote]

Pois é. Um JBoss da vida configurado corretamente bloquearia isso para você. Em outros containers ou AS teria de pesquisar e verificar como é possível.
Senão me engano, sempre que você digita uma URL e acessa diretamente pelo brownser, utiliza-se o método GET da Servlet.

Para tal, você pode testar se realmente seu método GET é invocado, caso seja, faça a validação.
Verifique se há usuário na sessão e caso não exista, direciona o usuário para uma página de erro.
É uma idéia.

Abraços.

Fiquei meio confuso…

não posso fazer um novo método dentro da DAO que verifica se é administrador ou não e tb retorna true ou false…

dai faço duas chamadas no meu servlet…

=)

é mais simples e acho q pode funcionar tb!

[quote=dombeck]Fiquei meio confuso…

não posso fazer um novo método dentro da DAO que verifica se é administrador ou não e tb retorna true ou false…

dai faço duas chamadas no meu servlet…

=)

é mais simples e acho q pode funcionar tb![/quote]

Claro que pode, se tu acha menos confuso e mais simples, faça.
Isso foi apenas uma sugestão. Só um detalhe, evite usar o ‘*’ em Select, busque apenas as colunas que precisa, pois vai estar trazendo informações desnecessária, dependendo o caso.

Abraços.

nel…

naquela sua sugestão da minha DAO ali deu um problema…

no finally

finally {
psmt.close();
rs.close();
con.close();
}

ele não reconehce o psmt.close() e o rs.close();
porém o con.close() sim

porque será?

[quote=dombeck]nel…

naquela sua sugestão da minha DAO ali deu um problema…

no finally

finally {
psmt.close();
rs.close();
con.close();
}

ele não reconehce o psmt.close() e o rs.close();
porém o con.close() sim

porque será?[/quote]

Foi um exemplo, tinha de ter modificado.
Veja:

try { String teste = "João"; } finally { teste = ""; }

A String ‘teste’ pertence exclusivamente ao bloco try - finally, e não a todo o método que esteja incluso esse trecho de código entende?
Para reconhecer, teria de fazer isso:

String teste = null; try { teste = "João"; } finally { if(null != teste) System.out.println("Nome: " + teste); }

Entendeu? :slight_smile:
Faça igual para todas as variavéis que citei para o seu Finally.

Abraços.

Essa parte ta resolvida!

Alguém mais tem sugestões sobre formas de permitir e bloquear usuários em JSPs?