Ajuda na parte do login do projecto

46 respostas
javawebjsftomcatprimefacesmysql
A

Boas colegas.
Preciso de umas orientações vossas visto que não sou experiente, estou em volta de um projecto web, usando jsf, primefaces, apache tomcat e paginas em formato xhtml e conectado a uma base de dados mysql. O projecto esta andar bem, porém um dos requisitos seria permitir a autenticação de usuarios atraves do login, é ai que estou com dificuldade, tenho procurado pela internet mas sempre aparece exemplos mas a usarem hibernate e outras tecnologias, o que parece que não se enquadra com o meu projecto por ser algo simples. gostaria de saber o que tenho de fazer para que cada usuario possa ter acesso ao sistema, visto que construi perfis para cada usuario, (são tres) e controlo sessão.

46 Respostas

M

Olá

Hibernate é para persistência de dados, ou seja, inserir os dados no banco.

Para controlar a sessão, vc pode ter uma classe Usuario e adicionar um atributo Usuario ao seu Bean SessionScoped ou adicionar o Usuario no contexto da aplicação através do ExternalContext.

Para autorização, você pode usar Phase Listener que é nativo do JSF ou então Spring Security.

A

Olá

Hibernate é para persistência de dados, ou seja, inserir os dados no banco.

Para controlar a sessão, vc pode ter uma classe Usuario e adicionar um atributo Usuario ao seu Bean SessionScoped ou adicionar o Usuario no contexto da aplicação através do ExternalContext.

Para autorização, você pode usar Phase Listener que é nativo do JSF ou então Spring Security.

Obrigado, como poderia implementar? Andei a pesquisar na internet e encontrei este tutorial http://benignosales.com.br/tutorial/criando-uma-pagina-de-login-completa-com-jsf-e-primefaces/, mas fiquei na duvida como poderia reaproveitar no meu projecto porque na classe bean do tutorial o autor usa @Named mas em todo o meu projecto usei sempre @ManagedBean, penso que teria de fazer alterações mas não sei realmente por onde começar… Deixarei as classes que já criei, talvez ajude um pouco

Classe de modelo de usuario

public class Usuario  {
	private int id;
	private String nome;
	private String login;
	private String senha;

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public void setLogin(String login) {
		this.login = login;
	}
	public String getLogin() {
		return login;
	}
	public String getSenha() {
		return senha;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}
}

Classe UsuarioDAO

public class UsuarioDAO {
	public void salvar(Usuario u) throws SQLException {
		StringBuilder sql = new StringBuilder();
		sql.append("Insert into usuario ");
		sql.append("(nome, login, senha) ");
		sql.append("values(?, ?, ? )");
		
		Connection conexao = Conexao.conectar();
		PreparedStatement stmt = conexao.prepareStatement(sql.toString());
		stmt.setString(1, u.getNome());
		stmt.setString(2, u.getLogin());
		stmt.setString(3, u.getSenha());
		stmt.executeUpdate();
					
	}
	
	public void excluir(Usuario u) throws SQLException{
		StringBuilder sql = new StringBuilder();
		sql.append("Delete from usuario ");
		sql.append("where idUsuario=?");
		
		Connection conexao = Conexao.conectar();
		PreparedStatement stmt = conexao.prepareStatement(sql.toString());
		stmt.setInt(1, u.getId());
		stmt.executeUpdate();
		
	}
	
	public void buscar(Usuario u) throws SQLException{
		StringBuilder sql = new StringBuilder();
		sql.append("select login, senha ");
		sql.append("from usuario ");
		sql.append("where login=? and senha=? ");
		
		Connection conexao = Conexao.conectar();
		PreparedStatement stmt = conexao.prepareStatement(sql.toString());
		stmt.setString(1, u.getLogin());
		stmt.setString(2, u.getSenha());
		stmt.executeUpdate();		
	}
}

Classe LoginBean

@ManagedBean(name = "MBLoginBean")
@SessionScoped
public class LoginBean implements Serializable {
	private Usuario usuario;

	public Usuario getUsuario() {
		return usuario;
	}
	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}	
}

Ou seja o meu problema acredito que esteja mesmo no tratamento da classe bean…

M

Você vai ter um formulário para fazer um login, certo?

Esse formulario vai conter os atributos da classe LoginBean, ou seja, o atributo usuario

Quando a sua página de login for visitada, caso o LoginBean não esteja na memoria, ele vai ser instanciado.

<p:outputLabel for="email" value="E-mail:"/>
<p:inputText  id="email" value="#{loginBean.usuario.email}"/>

<p:outputLabel for="senha" value="Senha:"/>
<p:password id="senha" value="#{loginBean.usuario.senha}"

<p:commandButton value="Entrar" action="#{loginBean.login()}"/>

Se você executar do jeito que a sua classe esta, vai gerar uma NullPointerException, pois vai ser tentando adicionar um valor ao atributo email e o seu objeto usuario vai estar nulo.

O seu login deve ter um método que faz a conexão ao banco.

Bom… Você tem um DAO que faz isso.

O jeito correto (no meu ponto de vista, quem sou eu né…) seria criar uma classe intermediária entre o Bean e o DAO, pois a classe DAO não pode ser referenciada no código (boas práticas).

Eu faria o seguinte:
Criaria um método que averiguasse se o usuário existe no banco, se existe, retorna ele então.

Criaria uma classe chamada UsuarioService, e teria um objeto UsuarioDAO. Criaria também um método que retorna Usuario, esse usuario viria de um método do UsuarioDAO.

E o bean teria um método que pega o retorno do método do UsuarioService, se o retorno for NULL, quer dizer que o usuario não esta cadastrado, se não for nulo, iguala o atributo usuario ao usuario retornado.

A anotação @ManagedBean esta ultrapassada ja, é recomendado usar o @Named do CDI (Estude que vale a pena, tem pouca coisa realmente necessária, então é rapidinho).

O CDI é bastante usado para Injeções de Dependências, através da anotação @Inject (A mais usada), você pode estar se pensando qual a vantagem? A vantagem é que é possível pegar o seu bean que está na mémoria, e coloca-lo como atributo de outro bean

@Named
@ViewScoped
public class CadastroProdutoBean {
    @Inject  
    private Usuario usuarioLogado;
}

Assim podendo acessar os atributos dele.

A outra forma de adicionar objetos na sessão, que é através de um map, confira abaixo:

FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("usuario", usuario);

Na linha acima eu adicionei o objeto usuário na sessão (que não necessariamente vai ser o objeto do seu LoginBean, na verdade você nem precisa adiciona-lo la).

Para recuperar o objeto da sessão, pode ser feito assim:

usuario = (Usuario) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("usuario");
A

Sim terá um formulário com campos para introduzir o nome de usuário e senha. Obrigado pela explicação Mike, mas na verdade fica um pouco difícil de entender de como aplicar relativamente a lógica e implementação não sou muito experiente para ser sincero. Será que podes ajudar a construir ficarei com uma ideia mais clara

M

Claro, eu te ajudo.

Se tiver dúvidas, só perguntar.

Primeiramente, eu colocaria o CDI no projeto.

No Tomcat tem que ter umas configurações extras para funcionar

A

Para ser sincero não fico muito seguro em começar em usar CDI, porque ainda nem sei bem como usar, provavelmente teria de alterar as outras classes bean para nao falar das configurações porque no meu projecto já esta conectado com a base de dados e a funcionar correctamente … certo??

M

Eu falei para usar CDI pq depois você só vai usar JSF com CDI.

Para fazer funcionar (depois arruma), cria uma instancia do seu DAO no bean.

Crie um método para fazer o login no bean.

No método de login, utilize o DAO para buscar o usuário no banco, e então atribua o retorno do método do DAO ao objeto usuario do bean.

Você também tem que alterar o seu método buscar. Se baseie no exemplo abaixo;

String sql = "select * from contatos where id =?";
    PreparedStatement stmt = this.con.prepareStatement(sql);
    stmt.setInt(1,id);
    ResultSet rs = stmt.executeQuery(); 
    if(rs.next){
        Contato contato = new Contato();  
        contato.setId(rs.getLong("id"));  
        contato.setNome(rs.getString("nome"));  
        contato.setEmail(rs.getString("email"));  
        contato.setEndereco(rs.getString("endereco"));  
        contato.setDataNascimento(data);
        return contato;
    }
    return null;
A

Fiquei sem entender um pormenor, ao alterar o método DAO buscar, como ira fazer a validação? Não terá que pegar a senha e usuário para lhe permitir entrar no perfil? A validação seria feita ao chamar o método que permitira tipo filtrar os campos que serviram para se autenticar? Ou seja o resultado do select

M

Ué, pra validar você vai tentar buscar o usuário no banco, você vai passar o e-mail e a senha na query.
Se a query trazer um registro, quer dizer que um usuário esta cadastro com aquele e-mail e senha
Se não trazer nenhum registro , então não tem ninguém cadastrado com aquele e-mail e senha, ou seja, o usuario vai ser nulo, se for nulo você exibe uma mensagem de erro.

No exemplo acima, foi usado o id como identificador, no seu caso você vai usar o e-mail e senha

A

A ideia seria fazer a autenticação com o nome de usuário e senha. Não sei se entendi mas então seria mais ou menos assim:

metodo DAO

public void ObterUsuario(Usuario u) throws SQLException{
StringBuilder sql = new StringBuilder();
sql.append("Select * from usuario ");
sql.append("where usuario=? and senha=? ");
Connection conexao = Conexao.conectar();
PreparedStatement stmt = conexao.prepareStatement(sql.toString());

ResultSet resultado = stmt.executeQuery();

if(resultado.next()){
Usuario u = new Usuario();
u.setUsuario(resultado.getString("usuario");
u.setSenha(resultado.getString("senha");
return u;

} else {
return null;  
}

}
M

Ai você tem que mudar o retorno do método, de void para Usuario

Ai no bean você faz assim:

@ManagedBean
@SessionScoped
public class UsuarioLogadoBean{
    ...
    public String login() {
        usuario = meuDAO.obterUsuario(usuario);
        
        if(usuario != null){
            return "index.xhtml";
        }
        else {
              FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "E-mail ou senha inválidos!", ""));
              return null;
        }
    }
}
A

Começo a entender, como eu tenho três perfis que são o admin (admin do sistema), administrador (quem controla) e funcionário (o controlado), devia encaminhar segundo uma condição pegando os valores dos campos e comparando resultaria se usa-se os metodos getters e setters do objecto? Tipo

public String login() {
            usuario = meuDAO.obterUsuario(usuario);
            
            if(usuario.getUsuario.equals("Joao") and usuario.getSenha("1234")){
                return "indexUsuarioA.xhtml";

            } else if(usuario.getUsuario.equals("Alberto") and usuario.getSenha("4567")){
              return "indexUsuarioB.xhtml";

    }else if(usuario.getUsuario.equals("Fernanda") and usuario.getSenha("8910")){
 return "indexUsuarioB.xhtml";}
            else {
                  FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "E-mail ou senha inválidos!", ""));
                  return null;
            }
        }
    }
M

Seria algo mais ou menos assim:

if(usuario.isAdmin()) {
//Faz algo
}
else if(usuario.isAdministrador()){
//Faz algo
}
else if(usuario.isFuncionario()){
//Faz algo
}
//E assim por diante
A
Seria algo mais ou menos assim:

if(usuario.isAdmin()) {
//Faz algo
}
else if(usuario.isAdministrador()){
//Faz algo
}
else if(usuario.isControlado()){
//Faz algo
}
//E assim por diante

O que estaria a pegar com o usuario.isAdministrador e os restantes?

M

O que vc quiser fazer.

O sistema é seu, você que decide o que tem que acontecer caso o usuario for admin ou adminstrador ou funcionario

A

Por acaso o is pega algum valor?

A

Na realidade estou pouco confuso como resolver este problema porque, criei três paginas index ou página principal, um para funcionário que tem uma barra de ferramentas diferente com o index do administrador e admin, o mesmo se aplica aos outros dois usuários, isto porque cada usuário teria funções diferentes no sistema, teria que encaminha-los para as suas respectivas paginas principais. E como poderia fazer? Tentei da maneira que exemplificaste mas nao resultou assinalou erro e da minha tambem deu erro…

A classe DAO ficou assim

public Usuario obterUsuario(Usuario u) throws SQLException {
		StringBuilder sql = new StringBuilder();
		sql.append("Select * from usuario ");
		sql.append("where usuario=? and senha=? ");

		Connection conexao = Conexao.conectar();
		PreparedStatement stmt = conexao.prepareStatement(sql.toString());

		ResultSet resultado = stmt.executeQuery();

		if (resultado.next()) {
			u.setUsuario(resultado.getString("usuario"));
			u.setSenha(resultado.getString("senha"));
			return u;
		} else {
			return null;
		}

	}

e a classe BEAN

public void login() {
		
		try {
			UsuarioDAO udao = new UsuarioDAO();
			usuario = udao.obterUsuario(usuario);
		
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
M

O is seria o get.

Quando se tem uma variável do tipo boolean, a convenção diz para usar is no lugar de get.

M

Qual seria o erro?

Tem a maneira correta, que é usar um autorizador para ser executado em todas as páginas que for acessar e tem a maneira para teste.

Vamos pro teste inicialmente:
Se você quer fazer um redirecionamente para uma página depois de efetuar um login, você tem que mudar o retorno do seu método para String, e então você retorna o nome da página ou pasta + página juntamente com a extensão

return “index.xhtml”;

A
public String login() {

	try {
		UsuarioDAO udao = new UsuarioDAO();
		usuario = udao.obterUsuario(usuario);
		if (usuario.getNome().equals("ayrton") && usuario.getSenha().equals("12345")) {
			return "indexFuncionario.xhtml";
		} else if (usuario.getNome().equals("raquel") && usuario.getSenha().equals("12345")) {
			return "indexAdmin.xhtml";
		} else if(usuario.getNome().equals("francisco") && usuario.getSenha().equals("12345")) {
			return "indexAdministrador.xhtml";
		}else {
			return null;
		}

	} catch (SQLException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	return null;
}

Assim não deu erro. Esta correcto? Esses valores estao armazenados na base de dados

M

Seria mais ou menos esse esquema mesmo, você ve qual usuário que é, e ai redireciona para uma certa pagina.

O mais correto seria no banco ter umas colunas informando o que o usuario é, ao invés de você checar nome e senha

A

Seria tipo criar uma coluna com níveis de acesso tipo 1, 2, 3 e uma tabela onde cada id representará uma tipo de usuario e haveria uma relação entre elas?

A

Na verdade deu um erro ao tentar logar, e não aceita o metodo login diz que tem que ser um metodo void…

<div id="login-panel">
		<h:form>
			<table>
				<tr>
					<td>Usuário</td>
			
					<td><p:inputText size="15" placeholder="Usuário" value="#{MBLoginBean.usuario.usuario}"/></td>
				</tr>



				<tr>
					<td>Senha</td>

					<td><p:password size="15" placeholder="Senha" value="#{MBLoginBean.usuario.senha}"/></td>
				</tr>

				<tr>
					<td colspan="2"><h:commandButton value="Entrar"
							style="horizontal-align:center;" actionListener="#{MBLoginBean.login}" /></td>
				</tr>

			</table>

		</h:form>
M

Muda de actionListener para Action

actionListener: executar uma lógica relacionada a view ou disparar uma ação antes de uma lógica de negócio. O método tem que ser void

Action é para navegação de páginas ou regra de negocio

A

Bem, ao trocar ele me direciona para uma pagina de erro ao usar o commandbutton da biblioteca do jsf, mas quando uso o commandbutton do primefaces não acontece nada. Aparece a seguinte pagina de erro.

HTTP Status 500  Internal Server Error
Type Exception Report

Message /pages/login.xhtml @67,95 value="#{MBLoginBean.usuario.usuario}": Target Unreachable, [usuario] returned null

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

javax.servlet.ServletException: /pages/login.xhtml @67,95 value="#{MBLoginBean.usuario.usuario}": Target Unreachable, [usuario] returned null
	javax.faces.webapp.FacesServlet.service(Unknown Source)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause

javax.el.PropertyNotFoundException: /pages/login.xhtml @67,95 value="#{MBLoginBean.usuario.usuario}": Target Unreachable, [usuario] returned null
	com.sun.faces.facelets.el.TagValueExpression.getType(Unknown Source)
	org.primefaces.util.ComponentUtils.getConverter(ComponentUtils.java:152)
	org.primefaces.renderkit.InputRenderer.getConvertedValue(InputRenderer.java:199)
	javax.faces.component.UIInput.getConvertedValue(Unknown Source)
	javax.faces.component.UIInput.validate(Unknown Source)
	javax.faces.component.UIInput.executeValidate(Unknown Source)
	javax.faces.component.UIInput.processValidators(Unknown Source)
	javax.faces.component.UIForm.processValidators(Unknown Source)
	javax.faces.component.UIComponentBase.processValidators(Unknown Source)
	javax.faces.component.UIComponentBase.processValidators(Unknown Source)
	javax.faces.component.UIViewRoot.processValidators(Unknown Source)
	com.sun.faces.lifecycle.ProcessValidationsPhase.execute(Unknown Source)
	com.sun.faces.lifecycle.Phase.doPhase(Unknown Source)
	com.sun.faces.lifecycle.LifecycleImpl.execute(Unknown Source)
	javax.faces.webapp.FacesServlet.service(Unknown Source)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause

javax.el.PropertyNotFoundException: Target Unreachable, [usuario] returned null
	org.apache.el.parser.AstValue.getTarget(AstValue.java:124)
	org.apache.el.parser.AstValue.getType(AstValue.java:58)
	org.apache.el.ValueExpressionImpl.getType(ValueExpressionImpl.java:174)
	com.sun.faces.facelets.el.TagValueExpression.getType(Unknown Source)
	org.primefaces.util.ComponentUtils.getConverter(ComponentUtils.java:152)
	org.primefaces.renderkit.InputRenderer.getConvertedValue(InputRenderer.java:199)
	javax.faces.component.UIInput.getConvertedValue(Unknown Source)
	javax.faces.component.UIInput.validate(Unknown Source)
	javax.faces.component.UIInput.executeValidate(Unknown Source)
	javax.faces.component.UIInput.processValidators(Unknown Source)
	javax.faces.component.UIForm.processValidators(Unknown Source)
	javax.faces.component.UIComponentBase.processValidators(Unknown Source)
	javax.faces.component.UIComponentBase.processValidators(Unknown Source)
	javax.faces.component.UIViewRoot.processValidators(Unknown Source)
	com.sun.faces.lifecycle.ProcessValidationsPhase.execute(Unknown Source)
	com.sun.faces.lifecycle.Phase.doPhase(Unknown Source)
	com.sun.faces.lifecycle.LifecycleImpl.execute(Unknown Source)
	javax.faces.webapp.FacesServlet.service(Unknown Source)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

O metodo bean ficou assim

public String login() {

		try {
			usuario = new Usuario();
			UsuarioDAO udao = new UsuarioDAO();
			usuario = udao.obterUsuario(usuario);
			if (usuario.getNome().equals("ayrton") && usuario.getSenha().equals("12345")) {
				return "indexFuncionario.xhtml";
			} else if (usuario.getNome().equals("raquel") && usuario.getSenha().equals("12345")) {
				return "indexAdmin.xhtml";
			} else if(usuario.getNome().equals("francisco") && usuario.getSenha().equals("12345")) {
				return "indexAdministrador.xhtml";
			}else {
				return null;
			}
			

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;

	}
M

Na sua página xhtml tem os campos usuario e senha não tem?

Bom… Você não postou o código todo, eu diria que JSF esta tentando inserir um valor no seu objeto e o seu objeto esta nulo (você inicializou no método login)

A

Sim tem

@ManagedBean(name = "MBLoginBean")
@SessionScoped
public class LoginBean implements Serializable {

	private static final long serialVersionUID = 5181306173238681349L;
	private Usuario usuario;

	public Usuario getUsuario() {
		return usuario;
	}

	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}

	public String login() {

		try {
			usuario = new Usuario();
			UsuarioDAO udao = new UsuarioDAO();
			usuario = udao.obterUsuario(usuario);
			if (usuario.getNome().equals("ayrton") && usuario.getSenha().equals("12345")) {
				return "indexFuncionario.xhtml";
			} else if (usuario.getNome().equals("raquel") && usuario.getSenha().equals("12345")) {
				return "indexAdmin.xhtml";
			} else if(usuario.getNome().equals("francisco") && usuario.getSenha().equals("12345")) {
				return "indexAdministrador.xhtml";
			}else {
				return null;
			}
			

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;

	}

}

Tenho que inicializar o usuário fora do método login??

M

Sim, isso foi falado no meu segundo post

Como que o seu objeto vai receber os valores dos campos, se ele esta null antes de ser chamado o metodo login?

A

O erro desapareceu ao tentar fazer o login, só que a página que devia aparecer não aparece simplesmente processa e mantém na mesma página de login e limpa os campos. Fui ver na console e aparece o seguinte erro:

java.sql.SQLException: No value specified for parameter 1
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:127)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1036)
	at mz.com.SistemaArmazemFCSP.DAO.UsuarioDAO.obterUsuario(UsuarioDAO.java:47)
	at mz.com.SistemaArmazemFCSP.Beans.LoginBean.login(LoginBean.java:32)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.el.parser.AstValue.invoke(AstValue.java:247)
	at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:267)
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(Unknown Source)
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(Unknown Source)
	at com.sun.faces.application.ActionListenerImpl.processAction(Unknown Source)
	at javax.faces.component.UICommand.broadcast(Unknown Source)
	at javax.faces.component.UIViewRoot.broadcastEvents(Unknown Source)
	at javax.faces.component.UIViewRoot.processApplication(Unknown Source)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(Unknown Source)
	at com.sun.faces.lifecycle.Phase.doPhase(Unknown Source)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(Unknown Source)
	at javax.faces.webapp.FacesServlet.service(Unknown Source)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:412)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1385)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Unknown Source)

Penso que seja no método DAO, certo? Fui confirmar mas não vi nenhum erro.

Aqui esta o método:

public Usuario obterUsuario(Usuario u) throws SQLException {
		StringBuilder sql = new StringBuilder();
		sql.append("Select * from usuario ");
		sql.append("where usuario=? and senha=? ");

		Connection conexao = Conexao.conectar();
		PreparedStatement stmt = conexao.prepareStatement(sql.toString());

		ResultSet resultado = stmt.executeQuery();

		if (resultado.next()) {
			u.setUsuario(resultado.getString("usuario"));
			u.setSenha(resultado.getString("senha"));
			return u;
		} else {
			return null;
		}

	}
M

O erro diz que não foi passado nenhum parametro para o sql.

Os seus parametros são os ‘=?’

Você tem que passar os valores para os parametros usuario e senha

Tipo assim:

PreparedStatement p = con.prepareStatement("select * from people where 
(first_name = ? or last_name = ?) and address = ?");
p.setString(1, name);
p.setString(2, name);
p.setString(3, address);

Se quiser saber mais, procure por: PreparedStatement Parameters

A

Bem agora fiquei um pouco confuso… Ao fazer isso terei que alterar novamente o meu método DAO, que esta assim :

public Usuario obterUsuario(Usuario u) throws SQLException {
		StringBuilder sql = new StringBuilder();
		sql.append("Select * from usuario ");
		sql.append("where usuario=? and senha=? ");

		Connection conexao = Conexao.conectar();
		PreparedStatement stmt = conexao.prepareStatement(sql.toString());

		ResultSet resultado = stmt.executeQuery();

		if (resultado.next()) {

			u.setUsuario(resultado.getString("usuario"));
			u.setSenha(resultado.getString("senha"));
			return u;
		} else {
			return null;
		}

	}
M

E que outra solução teria? Se esta errado (nao funciona) tem que alterar.

Você tem que passar os parametros para a query.

A

Bem, penso que fiz tudo errado…
Poderia seguir este tutorial e aproveitar para o meu sistema, visto que este projecto foi implementado em páginas em jsp, e as minhas páginas estao em xhtml… Haverá diferenças na implementaçao? . https://o7planning.org/en/11071/create-a-simple-login-application-and-secure-pages-with-java-servlet-filter#a11046510

A

Bem já consegui com uma ajuda efectuar o login, redirecionando consoante o nivel de acesso do usuario na base de dados. Mas o que falta é permitir criar sessao para cada usuario e a opção de terminar a sessao.

package mz.com.SistemaArmazemFCSP.Beans;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import mz.com.SistemaArmazemFCSP.DAO.FuncionarioDAO;
import mz.com.SistemaArmazemFCSP.DAO.UsuarioDAO;
import mz.com.SistemaArmazemFCSP.domain.Funcionario;
import mz.com.SistemaArmazemFCSP.domain.Usuario;
import mz.com.SistemaArmazemFCSP.util.Mensagens;

@ManagedBean(name = "MBLoginBean")
@SessionScoped
public class LoginBean implements Serializable {
	public Usuario usuario = new Usuario();
	public Funcionario funcionario = new Funcionario();
	public ArrayList<Usuario> itens;
	public ArrayList<Usuario> itensListados;
	public ArrayList<Funcionario> itensFuncionario;
	ExternalContext externalContext;

	private static final long serialVersionUID = -31701307345516338L;
	private static final Logger LOGGER = LoggerFactory.getLogger(Usuario.class);
	public static final String HOME_PAGE_REDIRECT = "/login.xhtml?faces-redirect=true";
	public static final String HOME_PAGE_ADMIN = "/indexAdmin.xhtml?faces-redirect=true";
	public static final String HOME_PAGE_FUNCIONARIO = "/indexFuncionario.xhtml?faces-redirect=true";
	public static final String HOME_PAGE_ADMINISTRADOR = "/indexAdministrador.xhtml?faces-redirect=true";
	public static final String LOGOUT_PAGE_REDIRECT = "/login.xhtml?faces-redirect=true";

	public Funcionario getFuncionario() {
		return funcionario;
	}

	public ArrayList<Funcionario> getItensFuncionario() {
		return itensFuncionario;
	}

	public void setItensFuncionario(ArrayList<Funcionario> itensFuncionario) {
		this.itensFuncionario = itensFuncionario;
	}

	public void setFuncionario(Funcionario funcionario) {
		this.funcionario = funcionario;
	}

	public Usuario getUsuario() {
		return usuario;
	}

	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}

	public ArrayList<Usuario> getItens() {
		return itens;
	}

	public void setItens(ArrayList<Usuario> itens) {
		this.itens = itens;
	}

	public ArrayList<Usuario> getItensListados() {
		return itensListados;
	}

	public void setItensListados(ArrayList<Usuario> itensListados) {
		this.itensListados = itensListados;
	}

	public void inserir() {

		try {

			UsuarioDAO udao = new UsuarioDAO();
			udao.salvar(usuario);
			itens = udao.listar();
			Mensagens.adicionarMensagemSucesso("Salvo com sucesso");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	public void excluir() {
		UsuarioDAO udao = new UsuarioDAO();
		try {
			udao.excluir(usuario);
			itens = udao.listar();
			Mensagens.adicionarMensagemSucesso("Excluído com sucesso");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public void editar() {
		
		try {
			UsuarioDAO udao = new UsuarioDAO();
			udao.editar(usuario);
			itens= udao.listar();
			Mensagens.adicionarMensagemSucesso("Editado com sucesso");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void prepararInserir() {

		try {
			usuario = new Usuario();
			FuncionarioDAO fdao = new FuncionarioDAO();
			itensFuncionario = fdao.listar();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	

	public void prepararEditar() {

		try {
			usuario = new Usuario();
			FuncionarioDAO dfao = new FuncionarioDAO();
			itensFuncionario = dfao.listar();

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	

	@PostConstruct
	public void prepararPesquisa() {

		try {
			UsuarioDAO udao = new UsuarioDAO();
			itens = udao.listar();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void prepararLogin() {
		usuario = new Usuario();
	}

	public String login() {
		Usuario usuarioRetornado = null;

		UsuarioDAO udao = new UsuarioDAO();
		try {
			usuarioRetornado = udao.buscarUsuario(usuario.getUsuario(), usuario.getSenha());
		} catch (SQLException e) {
			e.printStackTrace();
		}

		System.out.println(usuarioRetornado.getUsuario());

		if (usuarioRetornado.getRolestring().equals("Admin")) {

			FacesContext.getCurrentInstance().getApplication().getNavigationHandler()
					.handleNavigation(FacesContext.getCurrentInstance(), null, "indexAdmin.xhtml");

			return HOME_PAGE_ADMIN;

		} else if (usuarioRetornado.getRolestring().equals("Administrador")) {
			FacesContext.getCurrentInstance().getApplication().getNavigationHandler()
					.handleNavigation(FacesContext.getCurrentInstance(), null, "indexAdministrador.xhtml");

			return HOME_PAGE_ADMINISTRADOR;

		} else if (usuarioRetornado.getRolestring().equals("Funcionario")) {
			FacesContext.getCurrentInstance().getApplication().getNavigationHandler()
					.handleNavigation(FacesContext.getCurrentInstance(), null, "indexFuncionario.xhtml");

			return HOME_PAGE_FUNCIONARIO;

		} else {

			return null;
		}
	}
M

No meu segundo post, eu falei como faz para adicionar na sessão.

Vou colar aqui a parte:

Basicamente, se você usa SessionScoped você já tem objetos/atributos na sessão
Para recuperar esses objetos/atributos de um bean SessionScoped, você pode usar a anotação @Inject do CDI ou @ManagedProperty do proprio JSF, mas CDI é recomendado.

O código abaixo utiliza @Named que é o @ManagedBean do CDI, e dentro da classe eu estou usando @Inject para pegar o bean de sessão que esta na memoria e o atribuindo na minha classe

PS:Não precisa de get e set pro MeuBeanDeSessao

@Named 
@RequestScoped
public class SegundoBean {

    @Inject
    private MeuBeanDeSessao meuBeanDeSessao;
}

Ou então você pode adicionar o seu usuario na sessão (sem ser como um atributo do bean de sessão) depois de validar os dados de login.

FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("usuario", usuario);

E recuperar ele assim:

Usuario usuario = (Usuario) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("usuario");
A

O trecho para recuperar a sessão do usuario irei por abaixo do codigo para do trecho que introduz o usuario na sessão? Bem fiz assim estou certo?

public String login() {
		Usuario usuarioRetornado = null;

		UsuarioDAO udao = new UsuarioDAO();
		LoginSysDAO lsdao = new LoginSysDAO();; 
		try {
			usuarioRetornado = udao.buscarUsuario(usuario.getUsuario(), usuario.getSenha());
		} catch (SQLException e) {
			e.printStackTrace();
		}

		System.out.println(usuarioRetornado.getUsuario());

		if (usuarioRetornado.getRolestring().equalsIgnoreCase("Admin")) {

			FacesContext.getCurrentInstance().getApplication().getNavigationHandler()
					.handleNavigation(FacesContext.getCurrentInstance(), null, "indexAdmin.xhtml");
			FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("usuario", usuario);
			

			try {
				lsdao.inserirAdmin();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			return HOME_PAGE_ADMIN;

		} else if (usuarioRetornado.getRolestring().equalsIgnoreCase("Administrador")) {
			FacesContext.getCurrentInstance().getApplication().getNavigationHandler()
					.handleNavigation(FacesContext.getCurrentInstance(), null, "indexAdministrador.xhtml");
			FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("usuario", usuario);
			
			try {
				lsdao.inserirAdministrador();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			return HOME_PAGE_ADMINISTRADOR;

		} else if (usuarioRetornado.getRolestring().equalsIgnoreCase("Funcionario")) {
			FacesContext.getCurrentInstance().getApplication().getNavigationHandler()
					.handleNavigation(FacesContext.getCurrentInstance(), null, "indexFuncionario.xhtml");
			FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("usuario", usuario);
			
			try {
				lsdao.inserirFuncionario();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return HOME_PAGE_FUNCIONARIO;

		} else {
			
			return null;
		}
	}
M

A inserção esta correta.

Aqui:

FacesContext.getCurrentInstance().getApplication().getNavigationHandler()
					.handleNavigation(FacesContext.getCurrentInstance(), null, "indexAdministrador.xhtml");

Você esta fazendo um redirecionamento para uma página, só que mais abaixo você também faz através do return, usar as duas formas não faz muito sentido.

Não sei se você sabe, mas quando você chama um método no action, o retorno desse método diz ao JSF para qual página ele vai, no caso, você diz isso duas vezes.
É possível retornar null também, ai isso significa ficar na mesma página.

É bom também deixar o redirecionamento por último, caso você opte por usar handleNavigation, certifique de deixa-lo após adicionar o usuário na sessão.

O código que você postou faz três coisas:

  • Login
  • Adiciona o usuário na sessão
  • Redireciona para a página X

Você só vai pegar o usuário da sessão se for necessário na página X, do contrário você vai pegar só por pegar.

Mesmo que não tenha nada importante, é legal pegar pra Log do sistema. Então eu pegaria o usuário da sessão assim que o bean for criado, mas como fazer isso? Assim:

@PostConstruct
public void init() {
    usuario = (Usuario) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("usuario");
}

O método anotado com @PostConstruct não pode lançar exceções, mas pode trata-las no catch.
O método anotado com @PostConstruct é executado após o bean ser criado.
Se o Bean for escopo de sessão, o método será executado em toda requisição feita a esse bean.

A

Obrigado entendi, bem isso seria do tipo pegar o usuario para não permitir entrar numa determinada pagina sem fazer o login?.. Estou precisando de adicionar o controlo de acesso nas paginas, porque facilmente qualquer um conseguira entrar numa pagina atraves do endereco isso nao deveria ser possivel porque nao tem seguranca nenhuma e com isso tera acesso a todos os dados. Como posso fazer para impedir isso? Na verdade vi em alguns tutoriais mas fiquei sem saber como implementar, porque nao resultava

M

O JSF tem algo nativo para controle de acesso.

Da uma olhada nesse tópico, eu mesmo postei como faz

PS: Pode ter uma coisa ou outra escrito de maneira errada, pois escrevi boa parte do código no próprio editor do GUJ

EDIT: É necessário fazer uma configuração extra no arquivo faces-config, que é referenciar o PhaseListener através do Fully Qualified Name da classe, ou seja, o pacote + nome da classe, segue o exemplo:

<lifecycle>
    <phase-listener>seuPacote.seuPhaseListener</phase-listener>
</lifecycle>
A

Bem tentei adptar o codigo que postaste no artigo que referenciaste acima no meu, mas na configuração dá erro e diz que não consegue encontrar o fully qualified name da classe. Abaixo deixo o codigo da classe e do arquivo faces-config.

package mz.com.SistemaArmazemFCSP.phaseListener;

import java.sql.SQLException;

import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

import mz.com.SistemaArmazemFCSP.DAO.UsuarioDAO;
import mz.com.SistemaArmazemFCSP.domain.Usuario;

public class AutorizacaoPhaseListener implements PhaseListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private UsuarioDAO udao = new UsuarioDAO();
	private Usuario usuario;
	private FacesContext facesContext;
	private NavigationHandler nh;

	public FacesContext getFacesContext() {
		return facesContext;
	}

	public void setFacesContext(FacesContext facesContext) {
		this.facesContext = facesContext;
	}

	public Usuario getUsuario() {
		return usuario;
	}

	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}

	public UsuarioDAO getUdao() {
		return udao;
	}

	public void setUdao(UsuarioDAO udao) {
		this.udao = udao;
	}

	public NavigationHandler getNh() {
		return nh;
	}

	public void setNh(NavigationHandler nh) {
		this.nh = nh;
	}

	@Override
	public void afterPhase(PhaseEvent event) {
		facesContext = event.getFacesContext();
		nh = facesContext.getApplication().getNavigationHandler();
		Usuario usuario = (Usuario) facesContext.getExternalContext().getSessionMap().get("usuario");

		String paginaActual = facesContext.getViewRoot().getViewId();

		if (paginaActual.contains("/pages/*")) {
			Usuario usuarioRetornado = null;
			try {
				usuarioRetornado = udao.buscarUsuario(usuario.getUsuario(), usuario.getSenha());
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if (usuarioRetornado == null) {
				nh.handleNavigation(getFacesContext(), null, "index.xhtml?faces-redirect=true");

			} else if (usuarioRetornado.getRolestring().equalsIgnoreCase("Admin")) {

				nh.handleNavigation(getFacesContext(), null, "indexAdmin.xhtml?faces-redirect=true");

			} else if (usuarioRetornado.getRolestring().equalsIgnoreCase("Administrador")) {
				nh.handleNavigation(getFacesContext(), null, "indexAdministrador.xhtml?faces-redirect=true");

			} else if (usuarioRetornado.getRolestring().equalsIgnoreCase("Funcionario")) {
				nh.handleNavigation(getFacesContext(), null, "indexFuncionario.xhtml?faces-redirect=true");
			}

		} if (paginaActual.contains("/pages/index.xhtml?faces-redirect=true")) {
			Usuario usuarioRetornado = null;
			try {
				usuarioRetornado = udao.buscarUsuario(usuario.getUsuario(), usuario.getSenha());
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if (usuarioRetornado == null) {

				nh.handleNavigation(getFacesContext(), null, "/pages/index.xhtml?faces-redirect=true");
			}
		}

	}

	@Override
	public void beforePhase(PhaseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public PhaseId getPhaseId() {
		// TODO Auto-generated method stub
		return null;
	}

}

arquivo faces-config

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
	version="2.2">


	<lifecycle>
		<phase-listener>mz.com.SistemaArmazemFCSP.phaseListener.AutorizacaoPhaseListener</phase-listener>
	</lifecycle>


</faces-config>
A

O erro da configuração acabou por sair ao salvar. Mas não resultou, tem algo de mal no codigo?

M

:clap:t2:

if (paginaActual.contains("/pages/*")) {

Esse asterisco não vai funcionar da maneira que vc quer, pois na url nao vai estar o asterisco la

A

qual seria o endereço para puder englobar todas as paginas do projecto? A intenção seria aplicar em todas as paginas que o usuario apenas acessa ao fazer o login

M

Todas todas? Ai nem precisa de if, mas pode ser contains("")

Se você quer todas as páginas admin, você faz:

if (paginaActual.contains("/admin/"))

Se você quer todas as páginas admin que estão dentro da pasta ‘empresa2’, você faz:

if (paginaActual.contains("/empresa2/admin/"))

O método contains vai verificar se a String possui aquele conteúdo, no caso vai verificar se a url possuí aquele conteúdo.

Tenho certeza que na sua url não vem escrito faces-redirect=true

Então deixa apenas “/pages/index.xhtml”

Se você estiver com dúvida em relação a url, printa no console que ajuda bastante

System.out.println(paginaActual);
A

Não sei se entendi bem, mas, as minhas paginas estão dentro de uma pasta que é "pages", então terei que criar uma outra pasta dentro da pasta "pages" que é a pasta "admin" e introduzir la todas as paginas que quero fazer controlo de acesso ou criar uma pasta para cada nivel de acesso de usuario e colocar as paginas que o usuario terá acesso.

M

Exato!

Ex:
/pages/admin/relatorio.xhtml
/pages/admin/configuracoes.xhtml

Criado 6 de agosto de 2018
Ultima resposta 29 de ago. de 2018
Respostas 46
Participantes 2