Sessões concorrentes com Spring Security [RESOLVIDO]

0 respostas
2

Olá Galera, estou com um problema. Desenvolvo aplicações em JSF, com facelets, hibernate e banco postgre. Faço a autenticação do usuário através do SpringSecurity e preciso desenvolver uma funcionalidade da seguinte maneira.

Quando o usuário logar, eu preciso informar a ele se já existe alguma sessão aberta pra aquele usuário, e lhe dar a opção de matar a sessão que está aberta pra que ele possa logar.

A minha aplicação tem limite de uma sessão pra cada usuário.

Já pesquisei bastante na net e achei algumas coisas. Preciso de um método que me retorne todas as sessões abertas no servidor para que eu possa verificar se ele está em alguma delas, só que esse método é da classe SessionRegistryImpl, e eu não tenho uma instancia real dessa classe para trabalhar.

Alguém sabe como consigo isso? Ou alguma outra solução para resolver o meu problema?

Desde já agradeço…

[]´s


Galera, resolvi meu problema. Na verdade o Spring já te dá todas configurações para fazermos esse tipo de funcionalidade.

A primeira coisa a fazer é implementar uma classe do Spring chamada SessionRegistryImpl. Essa classe é a que tem quase todos métodos que vamos usar. Um dos métodos dessa classe, o onApplicationEvent(), é o responsável por “pegar” todos eventos disparados com relação a sessão. Então começamos com a implementação desse método na classe e alguns ifs para pegarmos todos eventos disparados:

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.security.concurrent.SessionRegistryImpl;
import org.springframework.security.event.authentication.AuthenticationSuccessEvent;
import org.springframework.security.event.authentication.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.event.authorization.AuthorizedEvent;
import org.springframework.security.ui.session.HttpSessionCreatedEvent;
import org.springframework.security.ui.session.HttpSessionDestroyedEvent;

/**
 *
 * @author Lázaro
 */
public class SafeSessionRegistryImpl extends SessionRegistryImpl {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            System.out.println("EVENTO -> ContextRefreshedEvent");
        } else if (event instanceof HttpSessionCreatedEvent) {
            System.out.println("EVENTO -> HttpSessionCreatedEvent");
        } else if (event instanceof AuthorizedEvent) {
            System.out.println("EVENTO -> AuthorizedEvent");
        } else if (event instanceof AuthenticationSuccessEvent) {
            System.out.println("EVENTO -> AuthenticationSucessEvent");
        } else if (event instanceof InteractiveAuthenticationSuccessEvent) {
            System.out.println("EVENTO -> InteractiveAuthenticationSucessEvent");
        } else if (event instanceof HttpSessionDestroyedEvent) {
            System.out.println("EVENTO -> HttpSessionDestroyedEvent");
        } else {
            System.out.println("EVENTO -> foi disparado um evento desconhecido -> " + event.getClass());
        }
        super.onApplicationEvent(event);
    }

}

Podemos reparar que os eventos seguem uma sequencia. Resumidamente, o Spring cria a sessão, autoriza e autentica. Depois de Autenticado temos acesso a todas sessões do usuário em questão. O código que usei foi o seguinte:

@Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            System.out.println("EVENTO -> ContextRefreshedEvent");
        } else if (event instanceof HttpSessionCreatedEvent) {
            System.out.println("EVENTO -> HttpSessionCreatedEvent");
        } else if (event instanceof AuthorizedEvent) {
            System.out.println("EVENTO -> AuthorizedEvent");
        } else if (event instanceof AuthenticationSuccessEvent) {
            System.out.println("EVENTO -> AuthenticationSucessEvent");
        } else if (event instanceof InteractiveAuthenticationSuccessEvent) {
            System.out.println("EVENTO -> InteractiveAuthenticationSucessEvent");
            try {
                // aqui criamos um objeto pra armazenar o contexto do Spring. //
                SecurityContext sc = SecurityContextHolder.getContext();
                // agora armazeno o id da sessão atual através de um método da classe SessionRegistryUtils e da autenticação obtida do contexto. //
                idSessao = SessionRegistryUtils.obtainSessionIdFromAuthentication(sc.getAuthentication());
                // depois pegamos um array com todas SessionInformation do usuário que acabou de logar. Usamos um método desta própria classe para isso. //
                SessionInformation[] sessoes = this.getAllSessions(SessionRegistryUtils.obtainPrincipalFromAuthentication(sc.getAuthentication()), true);
                // essa iteração é feita para que possamos expirar as outras sessões que estiverem abertas. //
                for (SessionInformation si : sessoes) {
                    // testamos se a sessão é igual a sessão que acabamos de criar. //
                    if (!si.getSessionId().equals(idSessao)) {
                        this.removeSessionInformation(si.getSessionId());
                        this.getSessionInformation(this.getIdSessao()).expireNow();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (event instanceof HttpSessionDestroyedEvent) {
            System.out.println("EVENTO -> HttpSessionDestroyedEvent");
        } else {
            System.out.println("EVENTO -> foi disparado um evento desconhecido -> " + event.getClass());
        }
        super.onApplicationEvent(event);
    }

Vale lembrar que esse código faz com que depois de logado, expiramos todas as outras sessões que estiverem abertas. Você tem que configurar o spring de maneira a aceitar mais de uma conexão por usuário, pois do contrário não conseguimos autenticar e consequentemente não temos acesso as sessões do usuário.

Outro detalhe é que, como diz na documentação do spring security, nós pedimos para que uma sessão expire, mas o spring que gerencia isso. Quando “der” o filtro do spring faz com que essa sessão seja removida.

Aqui vai um link que me ajudou muito, é o da documentação oficial, onde você pode ver detalhe dos métodos usados e conhecer outras classes também.
http://static.springsource.org/spring-security/site/index.html

[]´s

Criado 26 de janeiro de 2010
Respostas 0
Participantes 1