Filtrando requisições em JSF com PhaseListener
Antigamente a forma mais comum para se criar uma forma de verificar a autorização das requisições feitas para determinado recurso de uma aplicação web era utilizando um filtro (Filter). Porém em Java Server Faces (JSF), podemos realizar esta tarefa de uma outra forma mais integrada, utilizando a interface PhaseListener.
Esta interface disponibiliza 3 métodos:
void afterPhase(PhaseEvent event); void beforePhase(PhaseEvent event); PhaseId getPhaseId();
No exemplo, irei demonstrar como utilizar o método afterPhase que tem por finalidade fazer o tratamento de uma notificação assim que o processamento de uma determinada fase acabar de ser concluída.
A idéia principal do listener será verificar se existe um atributo de sessão chamado “currentUser” que será uma instância de um objeto User e este representará o usuário logado na aplicação. Caso este atributo exista, o listener deixa o ciclo da pagina seguir, mas caso o atributo não exista o ciclo será interrompido e redirecionado para a página de login.
Também terá uma verificação para não fazer nenhuma verificação caso a página atual da requisição seja a página de login.
Aqui temos o código do PhaseListener:
package com.rodrigolazoti.filter;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpSession;
public class AuthorizationListener implements PhaseListener {
public void afterPhase(PhaseEvent event) {
FacesContext facesContext = event.getFacesContext();
String currentPage = facesContext.getViewRoot().getViewId();
boolean isLoginPage = (currentPage.lastIndexOf("login.jsf") > -1);
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true);
Object currentUser = session.getAttribute("currentUser");
if (!isLoginPage && currentUser == null) {
NavigationHandler nh = facesContext.getApplication().getNavigationHandler();
nh.handleNavigation(facesContext, null, "loginPage");
}
}
public void beforePhase(PhaseEvent event) {
}
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
}
Note que o redirecionamento é feito por uma navegação configurada no arquivo faces-config.xml. Esta configuração é algo como:
<navigation-rule> <from-view-id>/*</from-view-id> <navigation-case> <from-outcome>loginPage</from-outcome> <to-view-id>/login.xhtml</to-view-id> </navigation-case> </navigation-rule>
Também deve-se incluir o listener no faces-config.xml:
<lifecycle> <phase-listener>com.rodrigolazoti.filter.AuthorizationListener</phase-listener> </lifecycle>
E com isso já se tem um PhaseListener funcionando e filtrando as requisições da aplicação.
Related Posts
Bom dia,
Porque você usa um operador ternário para comparar um resultado, já boolean, de um binário?:
(currentPage.lastIndexOf(“login.jsf”) > -1) ? true : false;
A comparação > -1 já vai retornar true ou false, esse ternário é o mesmo que:
if(true){
return true;
}
else{
return false;
}
Abraços.
Você está correto Fernando!
Foi uma “bobiada” mesmo ao adaptar um código ja existente para este exemplo.
Já refatorei o código com sua dica.
Obrigado.
[]‘s.
Parabéns pela sua dica.
Bem simples e bem explicado, o que não ocorre com muitos que encontrei na net.
Implementei e funcionou da primeira.
Vlw.
Rodrigo parabéns pelo tutorial.
Estou começando a programar em JSF e esse tutorial ajudou a utilizar PhaseListener no lugar de Filter.
Abraço
Muito bom o tutorial. Parabéns.
Excelente exemplo!!! Simples e facil d implementar!!!
O que é isso no código: &&
Alexandre, essas tags estavam aparecendo, pois foi um problema que tive com o plugin que renderiza o codigo java, ja arrumei este problema.
[]‘s
Bastante esclarecedor.
Mas ta dandoum erro muito estranho aqui, na linha 15 quando dou um “facesContext.getViewRoot()” isso retorna null, lançando um NullPointerException.
Alguém saberia me dizer o porquê disso?!
Abraços!
Mandou bem no post!
E aproveitando que vc manja, existe alguma maneira de trocar o PhaseId para INVOKE_APPLICATION e de alguma forma recuperar o “outcome”?!
Valeu!!!
Muito bem explicado, parabéns!
Boa dia, eu testei esse codigo e tive um problema ao inserir :
seguranca.AuthorizationListener
o projeto nao compila mais : dando esse erro
AIL – Application at context path /ApoioProducaoMedica could not be started
O:sistemasJava65ApoioProducaoMedicanbprojectbuild-impl.xml:650: Deploy do módulo não foi realizado.
FALHA NA CONSTRUÇÃO (tempo total: 1 segundo)
Olá rodrigo, td bem?
Antes de tudo, agradeço por ter colocado esse tutorial na net, já que é mto difícil encontrar um tutorial sobre esse assunto na net.
O problema que eu tive na implementaçao, é que aogra, minha página de login nao está mais indo ao banco. Eu coloco o login e a senha e ele nao prossegue. E o mais interessante, é que não dá erro nenhum no console. Estou usando o eclipse, o bd do postgresql. Agradeço a atençao.
Bom dia Rodrigo, fiz um teste de implementação com esses códigos mas reparei o seguinte… se eu tento acessar uma página não sendo o login ele redireciona para o login, depois disso, ao invés de redirecionar pra onde eu mando ele volta para a página de login pedindo usuário e senha…
no terminal eu vejo que nem a validação ele faz, redireciona direto…
tem idéia de algo?
penso que dentro do afterPhase tem que existir um teste para saber se já existe um usuário logado…
certo?
obrigado. abs.
nao sei como voce testou o projeto, mas tenho uso o richfaces + facelets. primeiramente tive que trocar a pagina de jsf para xhtml lastIndexOf(“login.xhtml”) pois estava entrando em loop pois nao achava a pagina jsf, currentPage vem como xhtml. um segundo problema apareceu ao fazer a alteracao acima, simplemente o css dos componentes richfaces nao funcionam mais. tens ideia o que possa ser? excelete tutorial, forma mais simples de implementar o controle de usuario/sessao.
Olá Arthur, td bem?
Quando fiz esse tutorial também utilizei Richfaces+Facelets.
Se não me engano passei por este mesmo problema que você, mas agora não me lembro como resolvi, mas sei que tem solucão.
Vou procurar depois e ver se acho ok.
[]‘s
descobri a solucao, nao sei se é a melhor, mas enfim.. na condicao onde é avaliada se é pagina de login e usuario esta autenticado, deve-se deixar passar as requisicoes dos .xcss. só passei pra deixar registrado pra quem enfrentar os mesmos problemas. []s
Qual a vantagem de utilizar PhaseListener ao invés de Filter??
pergunto isso pq uso Filter muito bem aqui, e esses dias tenho que começar a trabalhar com JSF. Filter não funciona com JSF?? qual a real vantagem do PhaseListener??
Tentei implementar o PhaseListener em minha aplicação mas ocorre que não está retornando o atributo currentUser na linha: Object currentUser = session.getAttribute(“currentUser”);
No meu managed bean eu coloquei a seguinte sintaxe:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(“currentUser”, user);
Mesmo assim retorna sempre null, já tentei colocar no faces-config.xml o scope para request e session e ambos ocorrem o mesmo problema.
Alguém pode me ajudar?
Obrigado,
Edi Nei
Olá, só um detalhe, se o contexto do seu jsf for tipo *.jsf e o usuário digitar o endereço como xhtml, ou seja fora do contexto, ai haverá uma falha de segurança pois PhaseListener não será invocado.
[...] 1.) http://www.rodrigolazoti.com.br/?p=56 [...]
arthur
Poderia explicar melhor como foi essa solução ? Estou com o mesmo problema.
Alguém sabe como crio um objeto logado?
Abraço a todos
[...] Outro exemplo da utilização do PhaseListener pode ser visto aqui. Like this:LikeBe the first to like this [...]