Neste post vou falar sobre um assunto um pouco trivial e que qualquer iniciante no framework JSF pode se perder: As fases do JSF e onde interceptar a navegação para que o usuário realize a autenticação.
É importante que você saiba o que é JSF e como configurá-lo em seu editor, aqui estarei utilizando o Eclipse, caso não saiba como configurar em seu editor, ao final, deixarei alguns links para lhe ajudar.
Vamos la =) .
Fases do JSF
O JSF funciona através de fases que são invocadas a partir do momento que abrimos uma página.
Então, o JSF executa um processo para coletar as informações, validar e criar a página de resposta que será enviada ao usuário.
Este processo é composto por 6 fases:
Restore View
Fase onde o JSF criará uma árvore de componentes, contendo um objeto para cada componente visual do formulário e, se for a primeira exibição da página, ele pula todas as fases e vai para a Render Response.
Se a página já foi exibida, o framework buscará pela árvore já existente.
Apply Request Values
Nesta fase, o framework pega os valores do formulário, eles são recebidos como Strings independente do tipo.
Process Validation
O JSF converte os valores existentes para os tipos que estão vinculados nas propriedades dos Managed Beans.
Após a conversão, é feita a validação desses valores.
Se ocorrer algum erro em qualquer dessas etapas, o JSF redireciona para a fase Render Response.
Update Model Values
Os dados convertidos são colocados nos objetos Managed Beans que estão vinculados.
Invoke Application
O método do atributo action que está vinculado a algum botão que foi acionado é avalido pela Expression Language e seu valor é retornado.
Render Response
O JSF processa a página recebida pelas fases anteriores e gera o código XHTML para o usuário.
Criação do Login
Primeiramente vamos criar nosso xhtml com os campos e botões para login vinculado com um Managed Bean e outro xhtml para ser a página inicial após o login do usuário.
A página deve ter os campos vinculados a um Managed Bean chamado usuário e um botão vinculado a algum método para logar.
Este foi meu código, claro, há diversos meios diferente para se fazer o mesmo:
E este foi o resultado:
No método logar vou verificar se o usuário e a senha correspondem ao meu nome: “Julio”.
Caso o usuário ou a senha forem diferentes de “Julio”, exibirei uma mensagem informando que o usuário é inválido.
Em outros casos será invocado um DAO, que verificará se o usuário existe na base de dados ou o que for preciso.
Crie, também, uma página de resposta caso o usuário esteja correto.
Segue o código da classe Usuário:
E, também, o código do XHTML de resposta em caso de sucesso.
Testes
Vamos testar nossa página:
Primeiramente coloquei os campos de modo correto, ou seja, com os valores em “Julio”, e após pressionar o botão “Logar” a página de sucesso foi retornada como esperado.
Mas tem um problema, conseguimos acessarmos diretamente a página de sucesso, pois não há nenhuma validação se o usuário está logado. Em casos de sistemas grandes, isso pode ser um enorme problema, pois qualquer usuário poderia ter acesso a informações não permitidas.
Correção
Devemos criar um login que valide se o usuário já está no sistema, então vamos criar uma classe que sirva como ouvinte entre as fases do JSF.
Para isto, é preciso:
- Criar uma classe que implemente a interface PhaseListener;
- Registrar no faces-config.xml.
Criarei uma classe chamada “Listener” que implementa a interface PhaseListener.
Esta interface possui 3 métodos:
- beforePhase: código que será executado antes do processamento da fase;
- afterPhase: código que será executado após o processamento da fase;
- getPhaseId: retorna um Enum com o nome da fase atual.
Devemos implementar nosso método para verificar se o usuário está logado no método “afterPhase”.
Para verificar se a página que está sendo acessada é diferente da página “login.xhtml” devemos pegar a instância atual do “FacesContext” e, partir dele, pegar o ViewRoot e o ViewId que contém o nome da página atual:
Após isto, é preciso verificar se o usuário está logado, isto pode ser feito com um atributo booleano na classe Usuario ou verificar se os parâmetros estão de acordo com o que queremos, vou utilizar esta segunda opção.
Para pegar o objeto Usuario que queremos, devemos utilizar o objeto “Application” a partir do FacesContext atual, através do método “getApplication”.
Então utilizamos o método “evaluateExpressionGet” do objeto “Application”:
Agora aplicamos nossa validação, no meu caso apenas peguei o atributo usuario a partir do objeto Usuario atual e verifiquei se é diferente de “Julio”, se for, retorno a navegação para a página login.
Isto é feito a partir do objeto “NavigationHandler” conseguido a através do objeto “Application” e invoco o método “handleNavigation”, que altera o fluxo. Por último chamo o método “renderResponse” do FacesContext.
E, claro, devemos indicar ao Listener qual fase que desejamos interceptar, que no nosso caso é a “Restore View” indicando no método “getPhaseId”.
Para que funcione, precisamos registrar no faces-config.xml que ele é um Listener.
Agora ao tentarmos entrar na página de sucesso diretamente, ele não vai.
Para quem deseja obter a URL correta, apenas adicionar “?faces-redirect=true” ao final da String de redirecionamento no Listener:
Então:
Retorna:
Obtendo o resultado desejado.
Comente em caso de dúvidas ou falhas =D.
Em meu blog tem alguns outros artigos deste mesmo tipo, se deseja ver: https://jcdourado.github.io
Obrigado!!
Segue alguns links de artigos e alguns livros que ajudam nessa caminhada:
https://www.devmedia.com.br/jsf-session-criando-um-modulo-de-login/30975
https://www.devmedia.com.br/java-web-criando-uma-tela-de-login-com-jpa-jsf-primefaces-e-mysql/32456
https://www.universidadejava.com.br/materiais/jsf-tela-login/
Livro: JSF Eficaz – Casa do Código.