Como usar JSF + tela de login + proteção em páginas que só podem ser vistas após login

Pessoal, boa tarde!

Sou iniciante em JSF, essa semana comecei a assistir alguns vídeos no Youtube sobre JSF, porém quando não começam a explicação do meio já começam usando uma porrada de frameworks e aí acaba sendo complicado aprender algo simples. Em todo caso estou tentando me virar com algumas coisas, porém estou com dificuldades em criar uma tela de login, na verdade, consigo criar uma tela de login a qual após digitar login e senha nos campos o usuário é redirecionado para a página que eu quero, porém se eu colocar essa página que somente deveria acessar após login no navegador, ele irá abrir sem problema algum.

Como faço para proteger essa página e outras que somente podem ser abertas se o usuário tiver logado?
Gostaria também de saber como posso usar sempre os dados do usuário logado nas páginas. Por exemplo, no JSP eu uso request.getSession().getAtribute(“login”), já em JSF eu realmente não sei, já que no JSP eu faço isso com Servlet.

Segue o código do meu UsuarioBean.java:

package bean;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

import conexao.Conecta;

import modelo.Usuario;

@ManagedBean(name = "usuarioBean")
@RequestScoped
public class UsuarioBean {

	private Usuario usuario = new Usuario();
	
	FacesContext context = FacesContext.getCurrentInstance();
	
	public String localizar() {
		
		Conecta conecta = new Conecta();
		Connection conexao = conecta.abreConexao();
		PreparedStatement pstmLocaliza = null;
		ResultSet resultado = null;
		
		String sql = "SELECT * FROM usuario WHERE login = ? AND senha = ?";
		
		try {
			
			pstmLocaliza = conexao.prepareStatement(sql);
			
			pstmLocaliza.setString(1, usuario.getLogin());
			pstmLocaliza.setString(2, usuario.getSenha());
			
			resultado = pstmLocaliza.executeQuery();
			
			if (resultado.next()) {
				usuario.setLogin(resultado.getString("login"));
				usuario.setSenha(resultado.getString("senha"));
								
				return "logado";
			} else {
				context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"Login ou senha inválido!", ""));
				return null;
			}
			
			
		} catch (SQLException e) {
			context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"Erro ao localizar registro. Mensagem: " + e.getMessage(), ""));
			return null;
		} finally {
			try {
				pstmLocaliza.close();
				resultado.close();
				conexao.close();
			} catch (Throwable e) {
				context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"Erro ao fechar operação de Localização. Mensagem: " + e.getMessage(), ""));
				return null;
			}
		}
		
	}//fim localiza

	public Usuario getUsuario() {
		return usuario;
	}

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

Agora o código da minha página login.xhtml:

<!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"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">

<h:head>
	<title>Exemplo de JSF com banco de dados</title>
</h:head>

<h:body>
	<h:messages/>
	<h:form>
		<h:panelGrid columns="2">
			<h:outputLabel for="login" value="Login"/>
			<h:inputText name="login" value="#{usuarioBean.usuario.login}" required="true" requiredMessage="Digite o login!"/>
			
			<h:outputLabel for="senha" value="Senha"/>
			<h:inputSecret name="login" value="#{usuarioBean.usuario.senha}" required="true" requiredMessage="Digite o login!"/>
		</h:panelGrid>
		
		<h:commandButton id="cmdLogin" value="Logar" action="#{usuarioBean.localizar}"/>
	</h:form>
</h:body>

</html>

E agora o código da pagina que somente deve aparecer se o usuário estiver logado, no caso eu chamei esta página de logado.xhtml por ser uma aplicação teste para aprendizado:

<!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"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">

<h:head>
	<title>Exemplo de JSF com banco de dados</title>
</h:head>

<h:body>
<div>
	<h:outputText name="msg" value="#{usuarioBean.usuario.login}"/>
	<br />
	&lt;h:inputText id="login" value="#{usuarioBean.usuario.login}"/&gt;
&lt;/div&gt;
&lt;/h:body&gt;

&lt;/html&gt;

Estou desde as 7 da manhã desde que acordei tentando ver isso sem sucesso. Eu vi usando um framework, fiz e deu certo, mas realmente não quero usar deste jeito, quero aproveitar e quando o usuário logar já manter alguns dados dele em um Session por exemplo, porém não sei como fazer isso também em JSF.

Ficarei muito grato se puderem me ajudar com esses problemas.

Desde já sou agradeço.

Basta voce utilizar um Filter.

Se for JSF2 ao invés de usar web.xml adicione a seguinte anotação na declaração da classe do seu Filter

@WebFilter(servletNames = {"Faces Servlet"})

[code]package br.com.crm.filters;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import br.com.crm.bean.LoginBean;

public class LoginRedirectFilter implements Filter
{
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException
{
//arg2.doFilter(arg0, arg1);

  HttpServletRequest servletRequest = (HttpServletRequest)arg0;
  @SuppressWarnings("unused")
	HttpServletResponse servletResponse = (HttpServletResponse)arg1;
  HttpSession session = servletRequest.getSession();
  String uri = ((HttpServletRequest) arg0).getRequestURI();
  LoginBean loginTmp = (LoginBean)session.getAttribute("login");
  	

				
	try
	{
		if((uri.indexOf("secured") > 0) && (loginTmp == null))
		{
			String url = "/pages/login.jsf";
			arg0.getRequestDispatcher(url).forward(arg0, arg1);
			return;
		}
		else
			arg2.doFilter(arg0, arg1); 
	}
	catch (Exception e)
	{
		e.printStackTrace();
		arg2.doFilter(arg0, arg1);
	}
}

@Override
public void init(FilterConfig arg0) throws ServletException
{
}

public void destroy()
{
}

}[/code]

seu web.xml caso seja JSF 1

<filter>
  <filter-name>LoginRedirect</filter-name>
  <filter-class>br.com.crm.filters.LoginRedirectFilter</filter-class>
 </filter> 

 <filter-mapping>
  <filter-name>LoginRedirect</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

Olá amigo, muito obrigado pela ajuda!

Bom, eu criei o filtro como você comentou, mas eu realmente não sei como usá-lo, tem apenas 3 ou 4 dias que venho assistindo uns vídeos de JSF no Youtube, e tudo que sei sobre foi desses vídeos, a maioria deles não tinham exemplos práticos e quando tinha eram com um monte de frameworks, fora que tentei fazer um ou 2 e não rodou aqui, mesmo baixando os fontes, acredito que deve ser versão do framework diferente.

Poderia me dizer como faço para usar o filtro?

Por exemplo, com o JSP eu fazia verificação fácil na página JSP com <% %>, JSF eu realmente não sei como fazer e até agora não achei em lugar nenhum.

Vou postar o código que você me passou e fiz as alterações para minha classe, gostaria de sua ajuda se possível para preencher o conteúdo de init e destroy.:

package filter;

import java.io.IOException;  
import javax.servlet.Filter;  
import javax.servlet.FilterChain;  
import javax.servlet.FilterConfig;  
import javax.servlet.ServletException;  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import javax.servlet.http.HttpSession;  
import bean.UsuarioBean;  

@WebFilter(servletNames = {&quot;Faces Servlet&quot;})
public class LoginRedirectFilter implements Filter  
{  
    @Override  
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException,   ServletException  
    {         
        //arg2.doFilter(arg0, arg1);  
          
      HttpServletRequest servletRequest = (HttpServletRequest)arg0;  
      @SuppressWarnings(&quot;unused&quot;)  
        HttpServletResponse servletResponse = (HttpServletResponse)arg1;  
      HttpSession session = servletRequest.getSession();  
      String uri = ((HttpServletRequest) arg0).getRequestURI();  
      UsuarioBean usuarioTmp = (UsuarioBean) session.getAttribute(&quot;login&quot;);  
          
  
                      
        try  
        {  
            if((uri.indexOf(&quot;secured&quot;) &gt; 0) && (usuarioTmp == null))  
            {  
                String url = &quot;/pages/login.jsf&quot;;  
                arg0.getRequestDispatcher(url).forward(arg0, arg1);  
                return;  
            }  
            else  
                arg2.doFilter(arg0, arg1);   
        }  
        catch (Exception e)  
        {  
            e.printStackTrace();  
            arg2.doFilter(arg0, arg1);  
        }  
    }  
  
    @Override  
    public void init(FilterConfig arg0) throws ServletException  
    {
    }  
  
    public void destroy()  
    {  
    }  
}

Desculpe minha ignorância, mas realmente não sei como fazer praticamente nada com JSF. Ah sim, eu estou usando JSF2.

Mais uma vez muito obrigado, e se ainda puder ajudar…

Nesse post Validação de Login de Usuário com JSF e JAAS eu mostro como validar usuário via JAAS que é mais prático do que por filter. Você apenas configura e pronto, quem vai tomar conta do login será o próprio JBoss.

Caro jakefrog, olhei seu post, realmente não é complicado, eu já fiz a validação com Spring, mas eu realmente quero saber como faço sem frameworks (exceto o próprio JSF rss), ate porque com o Spring que foi bem parecido com o que você mostra, exceto por uns detalhes, eu dou permissão de acesso ao usuário em determinada página, mas se eu quiser depois pegar os dados dele na sessão? Realmente ficaria perdido outra vez, por isso quero aprender sem framework e no futuro quando tiver já caminhando melhor passo a usar frameworks de acordo com a necessidade.

Mais um detalhe, eu não uso JBoss rsss, uso o TomCat 7.0.22 rsss.

Eu vi no link que você postou como usar o Filter, porém com servlet… depois vou até dar uma fuçada maior lá, parece ter coisas interessantes.

Muito obrigado mesmo pela força.

Em todo caso, se puder me ajudar com o Filter aí… rss… ficarei ainda mais agradecido.

Abraço

Beleza então.

Nesse post aqui eu uso JSP, mas mostra como utilizar o Filter purão mesmo. [=

Autenticação de Usuários (Filter/Servlet) Você poderá aproveitar o Filter de lá. [=

[quote=jakefrog]Beleza então.

Nesse post aqui eu uso JSP, mas mostra como utilizar o Filter purão mesmo. [=

Autenticação de Usuários (Filter/Servlet) Você poderá aproveitar o Filter de lá. [=[/quote]

Valeu Jakefrog, vou usar o seu tutorial com o exemplo lá hoje para estudar.

Encontrei também umas apostilas da K19 no site do mesmo, na verdade tem mais de uma, eu baixei tudo referente a JSF e visualizei rápido, tem comentando sobre o Filter e outras coisas interessantes como o uso d Ajax já embutido no próprio JSF, que eu já sabia ter mas ainda não tinha estudado, isso é muito bom pois economiza tempo.

Vou la no seu blog agora ver o tutorial e depois vou ler a primeira apostila da K19, vou tentar começar hoje e terminar hoje ainda, são somente 157 páginas ou mais ou menos isso.

Para quer tiver interesse nas apostilas: http://www.k19.com.br/downloads/apostilas-java

E o tutorial do Jakefrog sobre Filter: http://uaihebert.com/?p=19

Mais uma vez muito obrigado!

Abraço