Login + Session no JSF

Pessoal, estou com um projeto em JSF e fiz uma página de login e senha com validação no banco, criptografia e tudo mais.

Preciso agora criar uma sessão para que o usuário possa realizar as operações dentro do sistema web. E quero bloquear caso ele não tenha permissão ou fique inativo por por exemplo 5 minutos (isso eu sei que dá pra configurar no web.xml).

Não tenho muita idéia de como fazer isso… Tem gente que usa Filter, outros usam Servlet mas não sei se seria o certo no JSF… Alguém pode me dar uma luz?

eu fiz assim

package com.estagio.controller;

import com.estagio.business.UsuarioBO;
import com.estagio.entidade.Usuario;
import java.io.IOException;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

/**
 * @author Cristian Urbainski
 * @since 01/05/2012
 */
@ManagedBean
@SessionScoped
public class UsuarioLogadoController {
    
    private Usuario user;
    private Boolean usuarioLogado;
    
    private static UsuarioLogadoController instance;

    @PostConstruct
    public void inicializa()
    {
        user = new Usuario();
        usuarioLogado = Boolean.FALSE;
        instance = this;
    }
    
    public static UsuarioLogadoController getInstance() throws Exception
    {
        if(instance == null)
        {
            throw new Exception("Não há usuario logado no sistema, Oh my god!");
        }
        return instance;
    }
    
    public void logout()
    {
        this.user = null;
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    }
    
    public void fazerLogin()
    {
        try {
            Usuario u = new UsuarioBO().efetuarLogin(user);
            
            if(u == null)
            {
                FacesContext.getCurrentInstance().addMessage(null, 
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erro", "Usuario não encontrado ou senha incorreta, tente novamente."));
            }
            else
            {
                usuarioLogado = Boolean.TRUE;
                user = u;
            }
            
        } catch (Exception e) {
            FacesContext.getCurrentInstance().addMessage(null, 
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erro", "Erro ao efetuar login, tente novamente."));
        }
    }
    
    public String getNomeUsuario() throws IOException
    {
        if(usuarioLogado)
        {
            return user.getFuncionario().getNmFuncionario();
        }
        
        FacesContext.getCurrentInstance().getExternalContext().redirect("/projetoEstagio/faces/paginas/login.xhtml");
        return "";
    }
    
    public Usuario getUser() {
        return user;
    }

    public void setUser(Usuario user) {
        this.user = user;
    }
    
}

quando o sistema é aberto eu vejo se existe usuario logado se existir exibo o index mas se naum existir redireciono a pagina para o login, a pagina efetuar login chama esse metodo efetuarLogin

Peraí, deixa eu ver se entendi.
Eu não preciso instanciar nenhum HttpSession por exemplo?
Pq eu sei que pra você fechar uma sessão, vc precisar dar um invalidate()… E vc faz isso no:

FacesContext.getCurrentInstance().getExternalContext().invalidateSession();

Então eu preciso/devo usar a instância do FacesContext pra fazer essas manipulações de sessão? Não precisa de servlet ou filter ou qualquer coisa do tipo?

Manolo, utilize o Filter to JSF. Cria um para controle de usuários.

Voce pode fazer por meio de filtro ou servlet, so que eu penso assim, se fazer com servlet ou filtro é necessário fazer configurações em arquivos .xml, para ser exato no web.xml e eu procuro evitar isso, porque se voce pode ter feito tudo certo e so esqueceu da configuração no xml o troço naum funciona, eu ja vi muito colega meu se quebrando por esquecer esse tipo de coisa, ai voce acaba naum sendo programador e sim configurador de coisas, por isso eu costumo fazer desse jeito para fugir do xml, alguns vao dizer que estou errado e outros podem concordar comigo, eu faço assim por julgar que assim é melhor, vc tem que ver o que acha melhor e implementar como voce achar melhor.

FacesContext por baixo dos panos deve manipular a HttpSession, naum tenho certeza, posso estar errado mas acho que é isso que ele faz.

Aqui tem um exemplo do login com filtro


package controle;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;
import modelo.dao.HibernateUtil;
import modelo.dao.UsuarioDao;
import modelo.entidade.Usuario;
import org.hibernate.Session;

/**
 * @author lucas
 */
@ManagedBean
@RequestScoped
public class LoginHandler {
    Usuario usuarioLogado;
    
    public LoginHandler() {
        usuarioLogado = new Usuario();
    }

    public Usuario getUsuarioLogado() {
        return usuarioLogado;
    }

    public void setUsuarioLogado(Usuario usuarioLogado) {
        this.usuarioLogado = usuarioLogado;
    }
    
    public String login(){
        String irPara = "login";
        Session s = HibernateUtil.currentSession();
        UsuarioDao dao = new UsuarioDao(s);
        FacesContext facesContext = FacesContext.getCurrentInstance();
        
        Usuario usuarioNoBD = dao.localizeUsuarioPorNome(usuarioLogado.getUsername());
        if(usuarioNoBD==null){
            facesContext.addMessage("erro", new FacesMessage("Login não autorizado! Usuário não cadastrado."));
            usuarioLogado = new Usuario();
        }else if(!usuarioNoBD.getPassword().equals(usuarioLogado.getPassword())){
            facesContext.addMessage("erro", new FacesMessage("Login não autorizado! Senha incorreta"));
            usuarioLogado = new Usuario();
        }else{
            HttpSession sessaoHttp = (HttpSession) facesContext.getExternalContext().getSession(true);
            sessaoHttp.setAttribute("usuarioLogado", usuarioLogado);
            irPara = "index";
        }
        
        return irPara;
    }
    
    public String logout(){
        usuarioLogado = null;
        return "login";
    }
}
package controle;

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 modelo.entidade.Usuario;

public class LoginFilter implements Filter {

    private final static String FILTER_APPLIED = "_security_filter_applied";

    public LoginFilter() {
    }

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

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
        HttpServletRequest hreq = (HttpServletRequest) request;
        HttpServletResponse hresp = (HttpServletResponse) response;
        HttpSession session = hreq.getSession();

        hreq.getPathInfo();
        String paginaAtual = new String(hreq.getRequestURL());
        System.out.println(">>>>>>>" + paginaAtual);

        if ((request.getAttribute(FILTER_APPLIED) == null) 
                && paginaAtual != null 
                && (!paginaAtual.endsWith("login.xhtml")) 
                && (paginaAtual.endsWith(".xhtml"))) {
            request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

            String user = null;
            if (((Usuario) session.getAttribute("usuarioLogado")) != null) {
                user = ((Usuario) session.getAttribute("usuarioLogado")).getUsername();
            }

            if ((user == null) || (user.equals(""))) {
                hresp.sendRedirect("login.xhtml");
                return;
            }
            System.out.println(">>>>>> " + user);

        }
        // entrega a requisição para o proximo filtro  
        chain.doFilter(request, response);
    }
}

Configuração que ira no wev.xml


<!-- Filtro para identificar se o usuário está logado -->
    <filter>
        <filter-name>Login Filter</filter-name>
        <filter-class>controle.LoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Login Filter</filter-name>
        <url-pattern>*.xhtml</url-pattern>
    </filter-mapping>

E se o usuário tentar acessar suas paginas digitando na url? Esse seu Controller cuida disso?

Dificilmente vc vai ficar longe de XML ainda mais em aplicações EE. Configuração em XML não funciona? Não é vc que não esta conseguindo configurar? E quem disse que programador não configura XML?

Sim, no cabeçalho da pagina eu exibo o nome do usuario logado, se ele tentar acessar pela url o banner vai tentar pegar o nome do usuario logado vai ver que não ha usuario logado e vai redireciona-lo para o login

   public String getNomeUsuario() throws IOException
    {
        if(usuarioLogado)
        {
            return user.getFuncionario().getNmFuncionario();
        }
        
        FacesContext.getCurrentInstance().getExternalContext().redirect("/projetoEstagio/faces/paginas/login.xhtml");
        return "";
    }

se voce reparar no post anterior aonde post as classes inteiras esse metodo esta na classe UsuarioLogadoController.java

Cada um tem um jeito de fazer para decidir fazer como faço eu fiz desse jeito e com xml decidi fazer assim por ser mais facil, so isso cada um gosta de fazer a uma coisa de um jeito, é escolha propria so isso

Só uma dúvida mesmo, se eu souber o nome de um usuário logado, eu consigo invadir seu sistema ?

E onde vc está invalidando a sessão?

Não estou criticando a sua solução, só a sua forma de pensar, de que XML é um problema. Só estou dizendo que trabalhando com JavaEE vc não tem como fugir do XML.
XML funciona muito bem.

digaoneves: acredito que não, de uma olhada na classe que esta um pouco pra cima nos post UsuarioLogadoController, ela é um ManagedBean de Scopo de Sessao eu acredito que naum tem como voce burlar ela, o que voce me diz? ha como fazer isso ?
Isso é uma questão a ser testada poder ser o ponto falho da minha solução, eu acredito que não há como faze-lo.

gabrielfrios: repare na classe UsuarioLogadoController que postei anteriormente ela possui um metodo que invalida a sessao, vou posta-lo novamente, so peco que olhe melhor o codigo que eu postar antes de sair perguntando aonde faço as coisa, naum leve a mal, mas estava embaixo do seu nariz

    public void logout()
    {
        this.user = null;
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    }

Concordo, não como fugir do xml, hibernate, e tals mas gosto de evita-lo um pouco so isso.

Manolo, não precisa ficar bravo não, como disse anteriormente não estou criticando a sua implementação. O que eu disse é que você não pode criticar uma tecnologia por não saber usa-la.

Quando puder, da uma olhada no link abaixo:
http://www.coderanch.com/t/552518/JSF/java/Best-practice-secure-login-authorisation

Cara, so naum gosto que fiquei me pedindo coisa que estao debaixo do nariz das pessoas e elas naum vem isso realmente me deixa irritado, e a parte sobre " O que eu disse é que você não pode criticar uma tecnologia por não saber usa-la." concordo com voce, mas eu disse o que disse porque conheco os dois jeitos se voce naum reparou eu postei a mesma solucao usando filtro, mas uma vez sua desatenção esta evidente.

Dizer que você não sabe utilizar a tecnologia não foi baseada na implementação do filtro que você postou, pois um código desse você consegue na primeira pagina do google. Disse isso pelo fato de você dizer que não funciona e não demonstrar fatos que comprovem a sua afirmação.

da e dai ?

voce diz fazer algo assim, como fiz nesta outra aplicação

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.xsd">

	<security:http auto-config="true" use-expressions="true">
		<security:intercept-url pattern="/css/*" access="hasAnyRole('ROLE_ANONYMOUS','Administrador','Master','Padrão')" />
		<security:intercept-url pattern="/img/*" access="hasAnyRole('ROLE_ANONYMOUS','Administrador','Master','Padrão')" />
		<security:intercept-url pattern="/history/*" access="hasAnyRole('ROLE_ANONYMOUS','Administrador','Master','Padrão')" />
		<security:intercept-url pattern="/js/*" access="hasAnyRole('ROLE_ANONYMOUS','Administrador','Master','Padrão')" />
		<security:intercept-url pattern="/services/*" access="hasAnyRole('ROLE_ANONYMOUS','Administrador','Master','Padrão')" />
		<security:intercept-url pattern="/login.html" access="hasAnyRole('ROLE_ANONYMOUS','Administrador','Master','Padrão')" />
		<security:intercept-url pattern="/**" access="hasAnyRole('Administrador','Master','Padrão')" />
		<security:form-login login-processing-url="/j_spring_security_check" login-page="/login.html" default-target-url="/index.html" authentication-failure-url="/login.html?login_error=1" />
		<security:logout logout-url="/j_spring_security_logout" logout-success-url="/login.html" />
	</security:http>

	<security:global-method-security secured-annotations="enabled" />

	<security:authentication-manager>
		<security:authentication-provider>
 			<security:password-encoder hash="md5" />
			<security:jdbc-user-service data-source-ref="dataSource" users-by-username-query="select ds_login as username, ds_senha as password, tp_situacao as enabled from usuario where ds_login = ?"
				authorities-by-username-query="select us.ds_login as username, ds_papel as authority from usuario us, permissao pe, papel pa where us.id_usuario = pe.id_usuario and pe.id_papel = pa.id_papel and us.ds_login = ?" />
		</security:authentication-provider>
	</security:authentication-manager>

	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName" value="java:comp/env/jdbc/slu" />
		<property name="resourceRef" value="true" />
	</bean>
</beans>

usando jaas que é muito bom para isso

Nunca falei que não funciona, disse que acho mais ruim de usar por ter que configurar xml, naum coloque palavras em minha boca, seu imbecil. Ta sem argumento, ou o que eu uso assim porque quero use do jeito que vc quiser seu idiota, so apresentei a minha solucao se naum gosta do nem ai pra vc,

Suas palavras.

Mano não vou mais discutir com você. Já perdeu a linha e está tentando me agredir verbalmente. O tópico já está apto a ser bloqueado por sua causa. Quando você souber entrar em uma discussão como homem voltamos a conversar.

Mas claro se voce criar as classes e esquecer de por no web.xml o mapeamento do filtro ai naum funciona mesmo e se vc naum sabia disso e vc que estava falando merda sem conhecer nada, faca um teste espertao, mas se voce for um cara esperto e naum esquecer de nada claro que o troco funcioma esprtao