VRaptor + Session Timeout + Ajax

Bom Dia Pessoal,

Em meu projeto existe uma estrutura para verificar se determinado método pode ou não ser acessado pelo usuário.

A lógica é bem simples, utilizando @Intercepts, verificando se há um usuário logado na sessão, para as tentativas de acesso aos métodos anotados como @Restrito.

Até ai tudo ótimo e bonito. Porém, um item que não havia dado a devida atenção começou a me preocupar. A questão do Session TimeOut

As requisições feitas por chamadas diretas pelo navegador, caiam na rotina de verificação e eram redirecionados p/ local conforme configurado,
mas as requisições Ajax retornavam um status [color=red]302 - Moved temporarily[/color] , e não acontecia mais nada.

Pesquisei bastante sobre esse assunto e vi que não há uma solução que a comunidade tenha admitido como “padrão” p/ esse tipo de situação.

Portanto, venho compartilhar com vocês a solução que adotei, e aproveitar p/ pedir sugestões e comentários.

É bem possível que existam formas mais elegantes de fazer oq estou fazendo.

Tentei inclusive fazer um redirecionamento no @PreDestroy da minha classe @SessionScoped que guarda as informações de Login, mas ele não gostou muito de fazer um redirect a partir deste ponto, obviamente por questões do escopo. (session x request)

Bom, vamos ao que interessa… a solução aparentemente maravilhosa … (não sei porque, mas isso tá com uma cara de gambiarra… :twisted: )

:arrow: Primeiramente, a configuração do web.xml

<session-config> <session-timeout>30</session-timeout> </session-config>

:arrow: Definição da classe responsável por verificar se métodos anotados como @Restrito estão sendo requisitados por visitantes sem login

Caso seja validado que esta Classe realmente tem que interceptar a requisição, ele verifica ainda se o método está anotado como @ValidarComRedirectTo.
Neste caso ele entende que não é uma requisição Ajax, e faz um redirect normal na url do browser.
Se por ventura a classe não estiver anotada com @ValidarComRedirectTo ele envia um badRequest(), p/ chegar o código 400 na requisição Ajax, e não mais o 302 conforme comentado anteriormente.

[code]@Intercepts
public class AutenticacaoInterceptor implements Interceptor {

private final Result result;
private final LoginSession loginSession;

public AutenticacaoInterceptor(Result result, LoginSession loginSession) {
    this.result = result;
    this.loginSession = loginSession;
}

@Override
public boolean accepts(ResourceMethod method) {
    return !loginSession.isUsuarioLogado() && method.containsAnnotation(Restrito.class);
}

@Override
public void intercept(InterceptorStack stack, ResourceMethod method, Object resourceInstance) throws InterceptionException {
    if (method.containsAnnotation(ValidarComRedirectTo.class)) {
        result.redirectTo(AppController.class).login();
    } else {
        result.use(Results.status()).badRequest("Sessão Expirada ou Acesso Indevido!");
    }
}

}[/code]

:arrow: Registrando o comportamento das requisições Ajax ao receber um erro.

Coloquei este trecho de código em minha main.jsp (Página que contem os Menus, e onde os conteudo sao carregados) para definir como toda e qualquer requisição ajax deve se comportar ao receber um status [color=red]400 - bad request[/color]

$(document).ajaxError(function(event, jqxhr, settings, exception) { if(jqxhr.status == 400) { exibirAvisoTimeOut(); } });

A função exibirAvisoTimeOut() abre uma dialog avisando que o tempo de sessao expirou e que é necessário efetuar o login novamente e executa o comando window.location.reload();

Bom, sei que desta forma, qualquer requisição que dê errado, ele (navegador) vai pensar que é por conta do TimeOut.
Como todas as outras Exceções estão com um tratamento bem seguro em minhas Controllers, estou confiante que não terei problemas em deixar desta forma.

Esta foi a solução mais prática que encontrei p/ tratar a questão de privilégio de acesso junto com a questão da perda da sessão por timeout quando está envolvido requisições ajax.

Mas como falei no inicio, acredito que existam formas mais elegantes e com certeza até mais prática de se implementar isto no VRaptor.

Fico no aguardo de sugestões… :wink:

Grande Abraço

Eu já tive esse problema e o implementei de uma forma um pouco diferente:

Primeiro configurei um parâmetro isAjax = true toda vez que houver uma requisição ajax:

$(document).ready(function(){
   $.ajaxSetup({data:{isAjax:true}});
});

Depois eu verifiquei no meu interceptor se a requisição era ajax ou não:

@Override public void intercept(InterceptorStack stack, ResourceMethod method, Object resourceInstance) throws InterceptionException { if ("true".equals(request.getParameter("isAjax"))) result.use(status()).forbidden("You cannot access this page."); else redirect(method); }
E para finalizar fiz a mesma coisa, mensagem de erro padrão:

$(document).ajaxError(function(event, request, settings, thrownError) {
	$.error(message.error);
});

Valew Guerreiro… pelo visto… a gambiarra … não é tão gambiarra assim… 8)