Skip to content

PT BR 05.01. Sessões

Rafael Dipold edited this page Dec 30, 2013 · 1 revision

Aplicações Stateful

Aplicações Stateful são aplicações onde o estado do objeto deve ser guardado entre cada requisição. Uma forma de obter esse abordagem é a utilização de Sessões de Usuário (Session).

Usando Sessões

Uma Session pode ser obtida em qualquer momento na aplicação ao ser injetada pelo container CDI e utilizada para guardar e recuperar objetos:

@Controller
public SomeController {
    @Inject Session session;

    public void anyMethod() {
        session.setAttribute("someKey", someValue);
        String someValue = (String)session.getAttribute("someKey");
    }
}

Tempo de Vida da Sessão

O tempo de vida de uma sessão pode ser definida globalmente ou por sessão.

Para definir o tempo de vida das sessões globalmente, deve-se fazer isso na configuração inicial:

public class InitConfigStrategy implements ShiroInitConfigStrategy {
    @Override
    public void init(DefaultWebSecurityManager securityManager, AuthorizingRealm realm) {
        //3.600.000 milesegundos = 1 hora
        ((DefaultSessionManager)securityManager.getSessionManager()).setGlobalSessionTimeout(3600000);
    }
}

Para definir o tempo de vida de uma sessão individual, basta executar o método void setTimeout(long maxIdleTimeInMillis) de uma instância de Session.

Armazenamento de Sessões

Sempre que uma sessão é criada ou atualizada, seus dados precisam ser mantidos em um local de armazenamento para que ele seja acessível através da aplicação em um momento posterior. Da mesma forma, quando uma sessão é inválida e está mais sendo usado, ele deve ser excluído do armazenamento para que o espaço de armazenamento de dados de sessão não está esgotado.

O gerenciamento de sessão delega esta tarefa a um componente interno, o SessionDAO, que reflete o padrão de design do Data Access Object (DAO). O poder da SessionDAO é que você pode implementar essa interface para se comunicar com qualquer armazenamento de dados que desejar. Isso significa que seus dados de sessão pode residir na memória, no sistema de arquivos, em um banco de dados relacional ou armazenamento de dados NoSQL, ou qualquer outro local que você precisa. Você tem controle sobre o comportamento de persistência.

Você pode configurar qualquer implementação de SessionDAO como uma propriedade na instância de SessionManager padrão na inicialização do plugin:

public class InitConfigStrategy implements ShiroInitConfigStrategy {
    @Override
    public void init(DefaultWebSecurityManager securityManager, AuthorizingRealm realm) {
        ((DefaultWebSessionManager)securityManager.getSessionManager()).setSessionDAO();
    }
}

Por padrão, a configuração nativa do SessionManager do Apache Shiro é MemorySessionDAO que guarda todas as sessões apenas em memória volátil. Porém, a maioria das aplicações deve considerar o uso de uma implementação do SessionDAO que se utilize de um cache como o EHCache (EnterpriseCacheSessionDAO) ou sua própria implementação.

Mais detalhes sobre armazenamento e operações avançadas como validação, agendamento e clusterização de sessões podem ser vistos na documentação oficial do Apache Shiro.

Aplicações Stateless

Aplicações Stateless ocorrem quando a aplicação não guarda o estado dos objetos. Muitas arquiteturas de projeto são projetadas para que nenhum estado persistente possa existir entre as requisições, o qual naturalmente também não é permitido o uso de Sessões. Um exemplo conhecido dessa prática são as aplicações REST.

Mas essa exigência tem um custo o Subject não pode ser mantido entre as requisições. Isto significa que as aplicações com este requisito deve garantir que o Subject possa ser representado de alguma outra forma para cada requisição.

Isso é pode ser alcançado autenticando cada requisição/invocação/mensagem tratada pelo aplicativo. Por exemplo, aplicações web tipicamente impõe um HTTP Basic authentication no cabeçalho de cada requisição, permitindo que o navegador autentique todas as requisições em nome do usuário final.

Um exemplo prático dessa abordagem utilizando o VRaptor 4 pode ser feita adotando-se um interceptor que irá autenticar cada requisição:

@Intercepts
public class AuthenticationInterceptor {

    @Inject private Result result;
    @Inject private Subject subject;
    @Inject private HttpServletRequest request;

    @Accepts
    public boolean accepts(ControllerMethod method) {
        return method.containsAnnotation(Secured.class) || method.getController().getType().isAnnotationPresent(Secured.class);
    }

    @AroundCall
    public void around(SimpleInterceptorStack stack) {
        try {
            if (request.getHeader("Authorization") == null)
                throw new AuthorizationException("Access Denied! No authorization header received.");

            String username = //decode your authorization header
            String password = //decode your authorization header

            subject.login(new UsernamePasswordToken(username, password));

            stack.next();
        }
        catch (UnknownAccountException e) { result.use(status()).forbidden(e.toString()); }
        catch (IncorrectCredentialsException e) { result.use(status()).forbidden(e.toString()); }
        catch (LockedAccountException e) { result.use(status()).forbidden(e.toString()); }
        catch (ExcessiveAttemptsException e) { result.use(status()).forbidden(e.toString()); }
	catch (AuthenticationException e) { result.use(status()).forbidden(e.toString()); }
        catch (Exception e) { result.use(status()).forbidden(e.toString()); }
    }
}

E desativando o gerenciamento de sessão para que o Apache Shiro não crie sessões de usuário automaticamente:

public class InitConfigStrategy implements ShiroInitConfigStrategy {
    @Override
    public void init(DefaultWebSecurityManager securityManager, AuthorizingRealm realm) {
        DefaultWebSessionStorageEvaluator evaluator = new DefaultWebSessionStorageEvaluator();
        evaluator.setSessionStorageEnabled(false);
        ((DefaultSubjectDAO)securityManager.getSubjectDAO()).setSessionStorageEvaluator(evaluator);
    }
}