jsf - controle de sessões e controle de acesso.pdf

24
JSF: Controle de Sessões e Controle de Acesso Neste artigo, veremos como implementar dois recursos importantes em soluções web baseadas em Java EE e, mais especificamente, em JSF: o controle de sessões e de acesso a recursos e funcionalidades de acordo com o nível de permissão do usuário logado. Sessões e Controle de Acesso Neste artigo, veremos como implementar dois recursos bastante importantes em soluções web baseadas em Java EE e, mais especificamente, em JavaServer Faces: o controle de sessões e o controle de acesso a recursos e funcionalidades de acordo com o nível de permissão do usuário logado. Para isso, tomaremos como base uma aplicação cujo tema foi escolhido a dedo, aproveitando esta época de alta temporada em pleno verão brasileiro: um serviço de aluguel de chalés em Ubatuba, litoral norte do estado de São Paulo. Em que situação o tema é útil Este tema será útil sempre que o leitor, profissional de arquitetura e/ou desenvolvimento de software, optar pela plataforma Java EE, pela especificação JavaServer Faces e por sua implementação mais popular, o PrimeFaces, para a construção de aplicações web que envolvem o acesso de múltiplos usuários controlados através de sessões e com variados níveis de acesso às funcionalidades disponíveis. Aplicações web são constituídas, normalmente, de recursos e funcionalidades públicos, acessíveis a toda pessoa em contato com a Internet, e outros protegidos por níveis específicos de acesso. É muito comum vermos, em portais pela web, áreas restritas para candidatos em treinamento, funcionários, professores, administradores de sistemas, exibidas apenas mediante o fornecimento de credenciais com nível de acesso compatível com aquele previamente cadastrado em sistemas de informação relacionados. Outro comportamento muito comum em sistemas web é a exibição de determinadas informações sobre as quais o leque de operações permitidas varia de acordo com o tipo de usuário. Para exemplificar, imagine um sistema hipotético de controle acadêmico: enquanto professores possuem um perfil que os permite digitar as notas de seus alunos, estes últimos possuem um perfil um pouco mais restrito, que só os dá acesso à visualização de suas próprias notas. Embora a informação (nota) seja visível para ambos os perfis de usuário (professores e alunos), o escopo de atuação sobre ela varia sensivelmente. Há três características importantes no enredo acima: · Determinadas operações, para serem apresentadas e utilizadas, exigem autenticação de usuários; · As atividades de um usuário autenticado pertencem a um contexto particular de uso do sistema; · Pode haver atividades, em um sistema, que só devem ser apresentadas a tipos específicos de usuário. Todas elas serão abordadas ao longo deste artigo, na forma de um tutorial e uma aplicação tema. Para efeito de norteamento do leitor, trabalharemos com as premissas estabelecidas a seguir: · À primeira característica da lista acima, será atribuído o termo “controle de acesso”; · À segunda, atribuiremos os termos “sessão” e “controle de sessão”; · Por fim, à terceira característica, atribuiremos o termo “controle de perfis de acesso”.

Upload: anderson-kerlly

Post on 30-Nov-2015

1.671 views

Category:

Documents


8 download

TRANSCRIPT

Page 1: JSF - Controle de Sessões e Controle de Acesso.pdf

JSF: Controle de Sessões e Controle de Acesso

Neste artigo, veremos como implementar dois recursos importantes

em soluções web baseadas em Java EE e, mais especificamente, em

JSF: o controle de sessões e de acesso a recursos e funcionalidades

de acordo com o nível de permissão do usuário logado.

Sessões e Controle de Acesso

Neste artigo, veremos como implementar dois recursos bastante importantes em soluções web baseadas em

Java EE e, mais especificamente, em JavaServer Faces: o controle de sessões e o controle de acesso a

recursos e funcionalidades de acordo com o nível de permissão do usuário logado. Para isso, tomaremos

como base uma aplicação cujo tema foi escolhido a dedo, aproveitando esta época de alta temporada em

pleno verão brasileiro: um serviço de aluguel de chalés em Ubatuba, litoral norte do estado de São Paulo.

Em que situação o tema é útil

Este tema será útil sempre que o leitor, profissional de arquitetura e/ou desenvolvimento de software, optar

pela plataforma Java EE, pela especificação JavaServer Faces e por sua implementação mais popular, o

PrimeFaces, para a construção de aplicações web que envolvem o acesso de múltiplos usuários controlados

através de sessões e com variados níveis de acesso às funcionalidades disponíveis.

Aplicações web são constituídas, normalmente, de recursos e funcionalidades públicos, acessíveis a toda

pessoa em contato com a Internet, e outros protegidos por níveis específicos de acesso. É muito comum

vermos, em portais pela web, áreas restritas para candidatos em treinamento, funcionários, professores,

administradores de sistemas, exibidas apenas mediante o fornecimento de credenciais com nível de acesso

compatível com aquele previamente cadastrado em sistemas de informação relacionados. Outro

comportamento muito comum em sistemas web é a exibição de determinadas informações sobre as quais o

leque de operações permitidas varia de acordo com o tipo de usuário. Para exemplificar, imagine um sistema

hipotético de controle acadêmico: enquanto professores possuem um perfil que os permite digitar as notas de

seus alunos, estes últimos possuem um perfil um pouco mais restrito, que só os dá acesso à visualização de

suas próprias notas. Embora a informação (nota) seja visível para ambos os perfis de usuário (professores e

alunos), o escopo de atuação sobre ela varia sensivelmente.

Há três características importantes no enredo acima:

· Determinadas operações, para serem apresentadas e utilizadas, exigem autenticação de usuários;

· As atividades de um usuário autenticado pertencem a um contexto particular de uso do sistema;

· Pode haver atividades, em um sistema, que só devem ser apresentadas a tipos específicos de usuário.

Todas elas serão abordadas ao longo deste artigo, na forma de um tutorial e uma aplicação tema. Para efeito

de norteamento do leitor, trabalharemos com as premissas estabelecidas a seguir:

· À primeira característica da lista acima, será atribuído o termo “controle de acesso”;

· À segunda, atribuiremos os termos “sessão” e “controle de sessão”;

· Por fim, à terceira característica, atribuiremos o termo “controle de perfis de acesso”.

Page 2: JSF - Controle de Sessões e Controle de Acesso.pdf

Quando iniciarmos o tutorial, mais adiante, tais premissas ajudarão na identificação dos conceitos a elas

associados e seu respectivo tratamento dentro das tecnologias adotadas.

E já que falamos em tecnologia, vamos analisar os fatos sob esta ótica a partir de agora. O mercado nos

oferece opções variadas para atingirmos um nível satisfatório de segurança em sistemas baseados na

plataforma Java EE e também fora dela. Boa parte de todo o trabalho consiste na configuração de

bibliotecas, frameworks e outros recursos/sistemas relacionados, restando bem pouco a se fazer em termos

de implementação. Isto torna as coisas bem mais simples e ágeis, mas o fato é que nem sempre foi assim.

Toda esta facilidade de hoje é possível principalmente devido a alguns marcos muito significativos, dos

quais destacaremos dois:

· Lançamento do Java 5 com amplo suporte a anotações, tornando boa parte da configuração de sistemas, de

standalone a web (passando inclusive por mobile), muito mais simples;

· Lançamento do Java EE 6, com destaque para a API de Servlets 3.0 e CDI, permitindo a configuração de

listeners e filtros (e servlets também, naturalmente) a partir de anotações muito simples de compreender e

utilizar.

Além desses episódios essenciais da história da plataforma Java, é importante destacarmos a evolução

expressiva do framework Spring, especialmente do módulo Spring Security, com poderosos recursos para

controle de acesso, filtros, redirecionamento, sessões, dentre outros. Trata-se de um módulo relativamente

simples de se usar e muito eficaz dentro de seus propósitos, permitindo ao desenvolvedor incorporar em suas

aplicações um alto grau de robustez e confiabilidade. Atualmente, este módulo é um dos mais maduros do

Spring e tem sido aplicado em soluções de inúmeras empresas ao redor do mundo. Para mais informações

sobre o Spring e, especificamente, o Spring Security, consulte a seção Links ao final do artigo.

No tutorial a seguir, veremos como desenvolver uma aplicação em Java para a Web usando apenas os

recursos disponíveis na plataforma Java EE e, principalmente, na especificação JSF 2 e em sua

implementação mais popular, o PrimeFaces. A motivação para a definição deste escopo é sugerir ao leitor

uma reflexão acerca de uma prática de mercado muito comum nos dias de hoje, que classificaremos neste

artigo como subutilização. Frameworks são a grande onda da programação orientada a componentes, mas a

alta variedade de “peças” neste “jogo” tem trazido um efeito colateral preocupante: a combinação de muitos

frameworks para atender uma necessidade que, muitas vezes, seria sanada apenas por um ou dois deles.

O profissional dos dias de hoje conhece bem pouco o material com que trabalha em seu dia a dia, e algumas

combinações de tecnologias são frequentemente utilizadas meramente por terem sido, em algum momento,

rotuladas no mercado como garantias absolutas e inquestionáveis de qualidade, disponibilidade,

escalabilidade e segurança. Será mesmo? Será que, ao longo do tempo, a necessidade por agilidade não nos

tem trazido certa pressa pelo resultado, gerando deficiências e fragilidades para as quais temos dado,

erradamente, pouca atenção e importância?

Hoje observamos o Spring como padrão consolidado de mercado. Não que haja algum problema com este

framework, embora seu uso possa ser até substituído, em alguns casos, com recursos que o próprio Java EE

6 passou a oferecer (como o já mencionado CDI, acrônimo para Context and Dependency Injection). Para

integração entre sistemas, por exemplo, podemos fazer uso do Spring Integration, mas existem alternativas

bem interessantes e muito poderosas igualmente fáceis de aprender e empregar, como o Apache Camel, da

Fundação Apache (vide seção Links para referência a este projeto). A reflexão que estamos sugerindo para

o leitor da Java Magazine, principalmente para aqueles que já trabalham com (ou se interessam por)

desenvolvimento web, é: e se, um dia, Spring não fosse mais uma opção? Como as empresas e os

profissionais reagiriam a um movimento como este?

A preocupação maior deste texto que segue é exatamente esta: trazer para o leitor uma proposta, de certa

forma, minimalista, que explore em uma intensidade maior os recursos de uma especificação sólida como a

Java EE, como alternativa para essas combinações mercadológicas frequentemente encontradas por aí. Estas

combinações, normalmente, configuram um uso muito aquém do potencial que cada framework empregado

Page 3: JSF - Controle de Sessões e Controle de Acesso.pdf

possui, gerando normalmente um indesejável (e desnecessário) overhead com reflexos diretos no

desempenho e na complexidade de sistemas, além de exigir, naturalmente, profissionais gabaritados em uma

gama muito maior de tecnologias do que o realmente necessário para se colocar aplicações de qualidade em

execução.

A aplicação exemplo

A aplicação desenvolvida para este artigo engloba a exibição das acomodações de chalés localizados em

uma praia de Ubatuba, litoral norte do estado de São Paulo. Todos os recursos da aplicação estão protegidos

e requerem autenticação do usuário, que pode ser de três tipos. A Tabela 1 descreve brevemente cada um

deles, informando seus respectivos níveis de acesso aos recursos oferecidos pelo sistema.

Tabela 1. Tipos de usuário e seus níveis de acesso.

Trabalhando com sessões de usuário

Sempre que precisarmos registrar as operações realizadas por um usuário em uma aplicação web e,

principalmente, manter dados produzidos e/ou consumidos em memória ao longo do período em que este

usuário estiver em atividade, estará usando o que se entende, em computação, por sessão.

Uma sessão pode ser assim definida: “uma troca de informações semipermanente, interativa”, ou ainda: “um

diálogo, uma conversação ou reunião entre dois ou mais dispositivos ou um computador e um usuário”.

Observe a Figura 1. Esta é a página de entrada do sistema. Há três características que devemos garantir na

implementação deste sistema, referentes a esta página inicial:

1. A execução do sistema deve iniciar pela apresentação desta página;

2. Caso as credenciais oferecidas não correspondam a um usuário válido, o sistema deve permanecer

apresentando esta página;

3. O encerramento do uso (logout) deve resultar na apresentação desta página, com o respectivo

encerramento da sessão do usuário.

Observe agora a Figura 2, que nos mostra a estrutura do projeto. Em conjunto com a Figura 1, há ainda

uma terceira característica importante que devemos garantir que esteja coberta por nossa implementação:

1. Não havendo uma sessão estabelecida para o usuário, a única página que pode ser apresentada para o

usuário será a página inicial. Portanto, a digitação direta de qualquer endereço, referente a qualquer página

do sistema, deve ser sempre filtrada e verificada pelo sistema.

Page 4: JSF - Controle de Sessões e Controle de Acesso.pdf

abrir imagem em nova janela

Figura 1. Tela de login da aplicação.

O código-fonte da página apresentada na Figura 1 pode ser observado na Listagem 1. A ação de entrada no

sistema é processada a partir de um bean gerenciado, com escopo de sessão, chamado MbLogin e

identificado, na página, pela variável mbLogin. O código-fonte desta classe pode ser visto na Listagem 2.

Figura 2. Estrutura do projeto DevmediaApp.

Listagem 1. Página de login da aplicação.

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html PUBLIC

Page 5: JSF - Controle de Sessões e Controle de Acesso.pdf

"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://java.sun.com/jsf/html"

xmlns:p="http://primefaces.org/ui" >

<h:head>

<title>#{messages.LOGIN_TITULO}</title>

<h:outputStylesheet name="estilos.css" library="css" />

<style type="text/css">

.ui-widget{font-size:90% !important;}

</style>

</h:head>

<h:body style="background-image:url

('resources/images/summer-background-wallpaper.jpg');

background-color:transparent;">

<div id="tudo" align="center" style="background-color:transparent;">

<h:form style="background-color:transparent;">

<p:panel style="background-color: transparent;">

<p:panelGrid columns="2" style="background-color: transparent;" >

<h:outputLabel value="#{messages.LOGIN_USERNAME}"

styleClass="required_labels" />

<p:inputText value="#{mbLogin.usuario.username}"

size="45" id="campo_usuario" />

<h:outputLabel value="#{messages.LOGIN_SENHA}"

styleClass="required_labels"

goodLabel="#{messages.LOGIN_SENHA_MEDIA}" />

<p:password value="#{mbLogin.usuario.senha}"

maxlength="20" weakLabel="#{messages.LOGIN_SENHA_FRACA}"

strongLabel="#{messages.LOGIN_SENHA_FORTE}" id="campo_senha"

feedback="true" size="45" />

</p:panelGrid>

<p:commandButton ajax="false" value="#{messages.LOGIN_COMANDO_ENTRAR}"

styleClass="comandos" action="#{mbLogin.doLogin()}" />

<p:commandButton ajax="true" value="#{messages.LOGIN_COMANDO_LIMPAR}"

styleClass="comandos" action="#{mbLogin.limparTela()}"

update="campo_usuario campo_senha" />

</p:panel>

</h:form>

Page 6: JSF - Controle de Sessões e Controle de Acesso.pdf

</div>

</h:body>

</html>

Listagem 2. Bean gerenciado para operações de login, logout e controle de sessões.

/**

* Bean responsável por controlar operações de login, logout e controle de

* sessões de usuários.

*/

@ManagedBean

@SessionScoped

public class MbLogin implements Serializable {

private static final String LOGIN_SUCESSO = "login_sucesso";

public static final String LOGIN_FALHA = "login_falha";

public static final String SESSAO_INEXISTENTE = "sessao_invalida";

private static final String OUTCOME_LOGOUT = "logout";

public static final String USUARIO_SESSAO = "usuario";

private Usuario usuario;

private ControladorAcesso controladorAcesso;

public MbLogin() {}

@PostConstruct

public void inicializar() {

usuario = new Usuario();

controladorAcesso = new ControladorAcesso();

Logger.getLogger(MbLogin.class).log(Level.INFO,

">>>>>>>>>>>>> Inicializando um bean de login.");

}

/**

* Utilizado para tentativas de login no sistema, confrontando dados fornecidos

* pelo usuário com registros de usuários cadastrados.

*

* @return Outcome associado a fracasso ou sucesso na tentativa de login.

*/

public String doLogin() {

if (camposPreenchidos() && !isUsuarioLogado()) {

if (new ServicoLogin(usuario).executar()) {

// Descobrindo o tipo de usuário que está tentando acessar o sistema.

Usuario usuarioLogado = new ServicoCarregarUsuario().

carregarDados(usuario.getUsername(), usuario.getSenha()).get(0);

usuarioLogado.setStatus(Usuario.ATIVO);

Page 7: JSF - Controle de Sessões e Controle de Acesso.pdf

HttpSession sessao = (HttpSession) FacesContext.getCurrentInstance().

getExternalContext().getSession(true);

sessao.setAttribute(USUARIO_SESSAO, usuarioLogado);

controladorAcesso.configurarAcesso();

// Atualizando sistema de informação para informar que o usuário está logado.

new ServicoAtivarUsuario(usuarioLogado).cadastrar();

return LOGIN_SUCESSO;

}

}

return LOGIN_FALHA;

}

/**

* Utilizado para finalizar uma sessão de um usuário no sistema.

*

* @return Outcome associado a fracasso ou sucesso na tentativa de logout.

*/

public String doLogout() {

FacesContext context = FacesContext.getCurrentInstance();

HttpSession sessao = (HttpSession) FacesContext.getCurrentInstance().

getExternalContext().getSession(false);

Usuario usuarioSessao = (Usuario) sessao.getAttribute(USUARIO_SESSAO);

if (usuarioSessao != null) {

usuarioSessao.setStatus(Usuario.INATIVO);

new ServicoDesativarUsuario(usuarioSessao).cadastrar();

}

context.getExternalContext().invalidateSession();

return OUTCOME_LOGOUT;

}

/**

* Utilizado para verificar se as credenciais necessárias para realização do

* login foram preenchidas.

*

* @return <code>true</code> em caso de dados preenchidos.

* <code>false</code> caso contrário.

*/

private boolean camposPreenchidos() {

return (usuario != null && usuario.getUsername() != null

&& !"".equals(usuario.getUsername()) && usuario.getSenha() != null

&& !"".equals(usuario.getSenha()));

}

Page 8: JSF - Controle de Sessões e Controle de Acesso.pdf

/**

* Método utilizado para verificar se um usuário tentando logar na aplicação

* já não possui alguma sessão aberta em outro navegador ou outra aba. A

* aplicação está barrando múltiplos acessos simultâneos de um usuário.

*

* @return <code>true</code> se já existir uma sessão ativa para o usuário.

* <code>false</code> caso contrário.

*/

private boolean isUsuarioLogado() {

return new ServicoControleSessao(usuario).executar();

}

/**

* Limpa todos os dados da tela de login.

*/

public void limparTela() {

this.usuario = new Usuario();

}

public Usuario getUsuario() {

return usuario;

}

public void setUsuario(Usuario usuario) {

this.usuario = usuario;

}

public ControladorAcesso getControladorAcesso() {

return controladorAcesso;

}

}

Este bean gerenciado possui um método, doLogin(), dentro do qual a operação de entrada acontece. O

escopo de sessão de MbLogin garantirá que, ao longo de todo o tempo em que uma sessão de usuário esteja

válida e ativa, apenas uma instância desta classe seja utilizada, o que nos permite utilizá-la para manter

determinados estados da aplicação durante este período.

Este é um ponto que merece um pouco de nossa atenção. Beans gerenciados, que são classes cujo ciclo de

vida é mantido pelo próprio container (que pode ser um servidor de aplicações como JBoss ou GlassFish, ou

web servers como Jetty ou Tomcat), precisam ter o seu escopo de “validade” definido via configuração ou

anotação, e isto é o que definirá por quanto tempo este objeto ficará em memória e também em que

momento será criado. Apenas para relembrarmos, ou apresentarmos caso o leitor ainda não tenha

experiência com JSF, o conteúdo a seguir será dedicado a uma explicação sucinta sobre cada um dos

escopos:

· Escopo de requisição (request, @RequestScoped): beans gerenciados sob este escopo serão instanciados

a cada nova requisição enviada para o servidor, permanecendo em memória até o momento em que a

resposta é enviada para o cliente. A partir daí, este objeto é removido da memória, sendo destruído.

Comentaremos, em breve, sobre o ciclo de vida de requisições JSF, cujo diagrama está ilustrado na Figura

3;

Page 9: JSF - Controle de Sessões e Controle de Acesso.pdf

· Escopo de Sessão (session, @SessionScoped): este escopo atua como um compensador da natureza

stateless do protocolo HTTP, sendo utilizado para garantir que um bean gerenciado permaneça ativo ao

longo de toda uma experiência de uso do aplicativo (por exemplo, do momento do login ao momento do

logout), independente do número de requisições ocorridas;

· Escopo de Aplicação (application, @ApplicationScoped): este é um escopo ainda mais amplo que o de

sessão, pois garante que um bean gerenciado estará disponível do momento em que a aplicação é

inicializada até a sua parada. Um bean com escopo de aplicação estará disponível, dentro do tempo de vida

de uma aplicação, para todas as requisições de todas as sessões ativas. O espaço de memória que este objeto

alocará é, portanto, comum a um número variável de agentes, e a escolha deste escopo implica em um

cuidado ainda maior na implementação dos recursos que este bean disponibilizará para o sistema. Do JSF

2.0 em diante, todo bean gerenciado com escopo de aplicação pode ser instanciado em dois momentos:

quando a aplicação é acessada pelo primeiro usuário ou antes da exibição da primeira página da aplicação.

Neste último caso, existe um atributo chamado eager que pode ser ativado na própria anotação da classe do

bean gerenciado;

· Escopo de Visão (view): este escopo está presente somente a partir da versão 2.0 da especificação JSF e

garante que o bean gerenciado estará vivo em memória enquanto aquela página para o qual foi projetado

esteja sendo exibida. No momento em que uma nova página for apresentada ao usuário, este objeto será

destruído, pois já não haverá mais sentido em mantê-lo em memória. Como o leitor pode provavelmente

estar pensando a partir desta definição, este é um recurso que ajuda bastante no gerenciamento de memória

em casos de solicitações AJAX ao servidor, proporcionando maior dinâmica ao sistema como um todo.

Figura 3. Ciclo de vida de uma requisição JSF.

Feita esta pausa para uma breve descrição conceitual sobre o ciclo de vida de beans gerenciados do JSF,

retomemos a análise da aplicação-tema deste artigo.

Inicialmente, o sistema procura verificar se os campos estão preenchidos (através do método

camposPreenchidos()), e caso estejam, uma instância do serviço de login é criada para verificar a validade

do usuário junto ao banco de dados da aplicação.

Para efeito de ilustração de recursos do Java EE e do JSF, foi estabelecido um requisito de que não deverão

existir sessões simultâneas para um mesmo usuário. Para tornar isto possível, foi definido em banco de

dados, para a tabela de usuários, uma flag de controle que guarda exatamente a informação de sessão ativa.

Usamos a Tabela 2 para descrever como esta tabela de usuários foi projetada no banco de dados.

Page 10: JSF - Controle de Sessões e Controle de Acesso.pdf

A lógica para garantir este comportamento se encontra no método isUsuarioLogado(). Nele, instanciamos

um serviço de controle de sessão (classe ServicoControleSessão), que verificará se o registro deste usuário,

no banco de dados, está com sua flag de sessão “desligada”.

Tabela 2. Estrutura da tabela de usuários no banco de dados.

Caso o usuário não esteja logado em nenhum outro navegador, uma nova sessão será criada e esta instância

de usuário será, nela, gravada. Manter os dados do usuário na instância que representa a sessão de uso

permitirá, por exemplo, recuperá-los de qualquer outro ponto da aplicação, durante todo o tempo em que

esta sessão estiver ativa, aberta.

A classe central da especificação JSF é a javax.faces.context.FacesContext. Por ela, conseguimos obter

referências a elementos fundamentais de toda a especificação, como a aplicação, lista de mensagens, kit de

renderização e a raiz da árvore de componentes visuais (view root). Através deste objeto de contexto,

podemos também recuperar uma instância da classe ExternalContext

(javax.faces.context.ExternalContext), através da qual, então, conseguimos obter uma referência para a

sessão atual. O parâmetro booleano passado para o método getSession() desta classe indica que, caso não

exista uma sessão ativa, uma nova será criada. A documentação completa, com todos os seus detalhes, pode

ser encontrada na documentação oficial da Oracle (vide seção Links).

Assim que as credenciais de um usuário forem validadas pela aplicação, e sendo este um usuário conhecido,

estabelecer-se-á uma sessão para ele, válida do momento da operação de login até a respectiva operação de

logout. Ao longo deste período de tempo, todas as atividades que o usuário realizar estarão vinculadas a esta

sessão, este contexto particular e conhecido de uso da aplicação.

Sessões, em Java, são representadas pela abstração HttpSession, do pacote javax.servlet.http, e sua

principal utilidade é garantir a manutenção do estado de uma aplicação durante um contexto particular de

uso, uma vez que o protocolo HTTP, stateless por definição, não nos oferece este recurso.

Para facilitar a compreensão do conceito de sessão, imagine um carrinho de compras em portais como

Submarino ou Balão da Informática. Enquanto navegamos, temos a possibilidade de adicionar itens ao nosso

carrinho, que permanece com essas informações independentemente de quantas pesquisas façamos ou

quantas páginas visitemos ao longo da experiência de uso. O contexto de uso aqui é representado pelo

intervalo de tempo iniciado quando o usuário entra no portal até aquele em que, tendo feito todas as suas

compras, resolve encerrar a utilização dele.

Como antecipamos no texto, o sistema terá também uma operação de logout. Esta operação deve estar

disponível em todas as páginas, e para isto utilizamos o recurso de templates do JSF, através da

Page 11: JSF - Controle de Sessões e Controle de Acesso.pdf

implementação oferecida pelo PrimeFaces. Observe a Listagem 3, que contém esta estrutura básica das

páginas da solução.

Listagem 3. Template das páginas da aplicação.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns=”http://www.w3.org/1999/xhtml“

xmlns:h=”http://java.sun.com/jsf/html”

xmlns:f=”http://java.sun.com/jsf/core”

xmlns:p="http://primefaces.org/ui"

xmlns:ui="http://java.sun.com/jsf/facelets" >

<h:head>

<title>#{messages.APLICACAO_TITULO}</title>

<style type="text/css">

.ui-widget{font-size:90% !important;}

</style>

</h:head>

<h:body style="background-image:url

('resources/images/summer-background-wallpaper.jpg');

background-color:transparent;">

<h:form>

<p:layout fullPage="true">

<p:layoutUnit position="north" size="100" resizable="false" closable="false"

collapsible="false" >

<div align="center">

<font style="font-family: Verdana, sans-serif; color: green; font-size:

60px;

font-weight: bolder;"> #{messages.HOME_TITULO} </font> </div>

</p:layoutUnit>

<p:layoutUnit position="south" size="50" resizable="false"

closable="false" collapsible="false" >

<div align="center">

<h:outputText style="text-align: center;"

value="#{messages.TEMPLATE_RODAPE}" />

</div>

</p:layoutUnit>

<p:layoutUnit position="west" size="200" header="#{labels.menu_opcoes}"

resizable="false" closable="false" collapsible="false">

<p:commandButton action="/home.xhtml" ajax="false"

style="width: 180px; margin-left: 5px;

Page 12: JSF - Controle de Sessões e Controle de Acesso.pdf

margin-right: 5px;" value="#{messages.TEMPLATE_MENU_INFO}"

/>

<br />

<p:commandButton action="/praia.xhtml"

style="width: 180px; margin-left: 5px; margin-right: 5px;"

value="#{messages.TEMPLATE_MENU_FOTOS_PRAIA}" ajax="false" /> <br />

<p:commandButton action="/chales.xhtml"

style="width: 180px; margin-left: 5px; margin-right: 5px;"

value="#{messages.TEMPLATE_MENU_FOTOS_CHALES}" ajax="false" /> <br />

<p:commandButton action="/admin.xhtml"

style="width: 180px; margin-left: 5px; margin-right: 5px;"

value="#{messages.TEMPLATE_MENU_AREA_ADMIN}" ajax="false"

rendered="#{mbLogin.controladorAcesso.permissaoFuncionario}" /> <br />

<p:commandButton action="#{mbLogin.doLogout()}" style="width: 180px;

margin-left: 5px; margin-right: 5px; background-color:crimson;

color: white; font-weight: bolder; "

value="#{messages.TEMPLATE_MENU_LOGOUT}" ajax="false" />

</p:layoutUnit>

<p:layoutUnit position="center" id="template_content" >

<ui:insert name="page_content" />

</p:layoutUnit>

</p:layout>

</h:form>

</h:body>

</html>

Nela, podemos ver o comando de logout configurado para acionar um método do bean gerenciado

MbLogin, responsável por operações de login e logout na aplicação. Este método é o

MbLogin.doLogout(). Inicialmente, a lógica contida nele recupera o contexto da requisição atual, através

do método estático FacesContext.getCurrentContext(). A partir daí, a instância de sessão atual é obtida, e

ocorre uma tentativa de recuperação do objeto que representa o usuário atualmente logado no sistema. Caso

exista, os dados deste usuário serão utilizados para atualizar a sua flag de sessão no banco de dados, através

de uma instância da classe de serviço ServicoDesativarUsuario. Por fim, a sessão é invalidada através da

referência para a instância de ExternalContext, já mencionada, e a saída produzida

(OUTCOME_LOGOUT) aciona uma regra de navegação do JSF que faz com que o sistema apresente a

página de login para o usuário.

O recurso de autenticação fica, assim, completo. Entretanto, outro ponto que merece destaque e precisa estar

coberto em nosso sistema é o controle do acesso ao sistema por parte de usuários que, porventura, conheçam

a estrutura básica do projeto (a qual, para este nosso exemplo, pode ser vista na Figura 2). Embora o sistema

esteja configurado para apresentar, em sua inicialização, a página de autenticação, qualquer pessoa poderia

tentar digitar, diretamente na barra de endereços do navegador, o caminho para qualquer página do sistema

que não seja a de login. No texto que segue, veremos como é possível filtrar requisições e impedir que este

Page 13: JSF - Controle de Sessões e Controle de Acesso.pdf

tipo de navegação seja realizado, salvo por usuários que tenham, previamente, se autenticado junto ao

sistema e, consequentemente, iniciado uma sessão de navegação.

Sempre que um usuário consumir uma determinada funcionalidade de um sistema em Java para a web,

estará enviando pela rede dados encapsulados na forma de uma requisição construída em cima do protocolo

HTTP. Para atividades de transformação de dados (cadastros, atualizações), o método comumente utilizado

é o POST, enquanto para recuperação de dados apenas para fins de leitura normalmente se utilizam do

método GET.

A unidade de processamento de requisições web, em Java, é conhecida como servlet. O termo “let”, em

computação, é normalmente utilizado para representar o diminutivo de um conceito, e servlets, neste

sentido, significam pequenos servidores, unidades lógicas que representam o servidor (ou, melhor dizendo,

atividades desempenhadas por ele).

A API de servlets (mais especificamente a classe javax.servlet.http.HttpServlet) estabelece um método

específico para cada método existente no protocolo HTTP (POST, GET, PUT, DELETE, OPTIONS,

HEAD, TRACE). A assinatura desses métodos segue um padrão que inicia com um prefixo “do”, seguido

pelo nome do método em questão. Logo, ao consultar a documentação da API (vide seção Links), o leitor

verá métodos como doPost(), doPut(), doDelete(), doOptions(), dentre outros.

No caso do JavaServer Faces, existe um servlet que age como um controlador central, e cuja implementação

se encontra na forma de uma classe chamada javax.faces.webapp.FacesServlet. Quando uma requisição

chega a este servlet, entra em um ciclo de vida definido dentro da especificação JSF, ilustrado na Figura 3.

A requisição percorre esta sequência de estados e a sinalização de cada mudança é realizada na forma de um

evento. O JSF possui uma família de classes para representação de eventos, tendo como unidade mais

genérica a classe javax.faces.event.FacesEvent. Como sabemos, o modelo de tratamento de eventos do

Java estabelece, para cada tipo de evento representado, uma interface com o contrato a ser seguido para o

tratamento deste evento, e que normalmente recebe a denominação de listener. A representação mais

genérica de listeners para eventos JSF está estabelecida na interface javax.faces.event.FacesListener.

Entretanto, para o caso de eventos relacionados a fases de uma requisição JSF, tal hierarquia não foi

respeitada. Para representar o evento de fase, temos a classe javax.faces.event.PhaseEvent (uma subclasse

direta de java.util.EventObject), e o listener correspondente foi definido através da interface

javax.faces.event.PhaseListener que, por sua vez, herda outras especificações de outras duas interfaces

utilitárias do Java, java.util.EventListener e java.io.Serializable.

Antes que esta última afirmação soe um pouco estranha para o leitor, revisitemos os conceitos de orientação

a objetos e, mais particularmente, como esses conceitos são implementados em Java. Eles enunciam que,

embora não possamos trabalhar com herança múltipla em classes de objetos, podemos tê-la, de certo modo,

aplicada a interfaces. Logo, é perfeitamente normal que uma interface como a PhaseListener estenda de

especificações pré-estabelecidas em outras duas interfaces (contratos, protocolos, como preferir).

Conforme já vimos anteriormente neste artigo, desejamos filtrar requisições para verificar, inicialmente, se

existe uma sessão ativa para o usuário. Mais que isso, desejamos redirecionar o usuário para a página de

entrada caso o usuário, ainda não “logado”, deseje acessar qualquer página interna da aplicação, via barra de

endereços do navegador.

Tudo começa através da implementação de um listener de fase, que pode ser visto na Listagem 4. O

primeiro ponto importante a ressaltar é que o método PhaseListener.getPhaseId() é implementado para

retornar sempre a instância que representa a fase RESTORE_VIEW (observe novamente a Figura 3, e note

que este é o primeiro estado em que a requisição entra). Isto faz com que apenas eventos relacionados a esta

fase sejam capturados, ignorando-se todos os demais eventos das fases subsequentes de uma requisição.

Já no momento posterior ao da fase, o que esta classe faz é identificar, através da instância de contexto

correspondente a esta requisição (FacesContext), se a página que se deseja acessar é a de login. Caso não

Page 14: JSF - Controle de Sessões e Controle de Acesso.pdf

seja, o próximo passo é verificar se, no objeto que representa a sessão, existe um usuário salvo (o que

configura, portanto, uma sessão ativa). Caso exista, permite-se a navegação desejada, e em caso contrário,

estabelece-se programaticamente um redirecionamento para a página de login através de uma instância de

javax.faces.application.NavigationHandler. O método usado para isto é o handleNavigation(), em que

são passados como parâmetros o contexto da requisição atual, uma ação e um outcome.

Navegação em JSF trabalha tanto com outcomes quanto com ações. Através de configuração, podemos

definir quais ações e resultados devem ser respeitados para que a aplicação navegue de uma página a outra.

Estas configurações podem ser observadas na Listagem 5. Nesta mesma listagem, podemos ver como se

configura um listener de fases para uma aplicação em Java para a web, através de um marcador <phase-

listener>, dentro do contexto de ciclo de vida da aplicação (representado pelo nó <lifecycle>). O código

correspondente ao listener, que já discutimos acima, pode ser consultado em detalhes na Listagem 4.

Para testar o comportamento do sistema, basta que executemos a aplicação e, ainda antes de executar o login

com um usuário válido, digitar o endereço completo de qualquer página existente no projeto direto na barra

de endereços do navegador web. Como, neste momento, ainda não existe uma sessão ativa, o sistema

redirecionará o usuário para a página de entrada.

Listagem 4. Listener de autenticação .

/**

* Responsável por manipular requisições de usuário, permitindo acesso ao

* conteúdo da aplicação somente no caso do usuário já ter se autenticado.

*/

public class ListenerAutenticacao implements PhaseListener {

private static final String PAGINA_LOGIN = "index.xhtml";

@Override

public void afterPhase(PhaseEvent event) {

FacesContext contexto = event.getFacesContext();

String pagina = contexto.getViewRoot().getViewId();

System.out.println(">>>>>>>>>>>>>>>>>

ListenerAutenticacao.afterPhase() "

+ "para página de ID " + event.getFacesContext()

.getViewRoot().getViewId());

if (!(pagina.lastIndexOf(PAGINA_LOGIN) > -1)) {

HttpSession sessao = (HttpSession)

contexto.getExternalContext().getSession(false);

Object usuario = sessao.getAttribute(MbLogin.USUARIO_SESSAO);

if (usuario == null) {

NavigationHandler navHandler =

contexto.getApplication().getNavigationHandler();

navHandler.handleNavigation(contexto, null,

MbLogin.SESSAO_INEXISTENTE);

}

}

}

Page 15: JSF - Controle de Sessões e Controle de Acesso.pdf

@Override

public void beforePhase(PhaseEvent event) {

if (event.getFacesContext().getViewRoot() != null) {

System.out.println(">>>>>>>>>>>>>>>>>

ListenerAutenticacao.beforePhase() "

+ "para página de ID " +

event.getFacesContext().getViewRoot().getViewId());

} else {

System.out.println(">>>>>>>>>>>>>>>>>

ListenerAutenticacao.beforePhase() "

+ "indicando view root ainda nula");

}

}

@Override

public PhaseId getPhaseId() {

return PhaseId.RESTORE_VIEW;

}

}

Listagem 5. Arquivo de configuração do JSF.

<?xml version='1.0' encoding='UTF-8'?>

<faces-config version="2.1" xmlns=“http://java.sun.com/xml/ns/javaee”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd">

<application>

<resource-bundle>

<base-name>br.com.devmedia.javamagazine.labels</base-name>

<var>messages</var>

</resource-bundle>

</application>

<navigation-rule>

<description>Regra de navegação para operação de login

</description>

<from-view-id>/index.xhtml</from-view-id>

<navigation-case>

<from-outcome>login_sucesso</from-outcome>

<to-view-id>/home.xhtml</to-view-id>

<redirect />

</navigation-case>

<navigation-case>

<from-outcome>login_falha</from-outcome>

<to-view-id>/index.xhtml</to-view-id>

Page 16: JSF - Controle de Sessões e Controle de Acesso.pdf

<redirect />

</navigation-case>

</navigation-rule>

<navigation-rule>

<description>Regra de navegação para operação de logout

</description>

<from-view-id>/*</from-view-id>

<navigation-case>

<from-outcome>logout</from-outcome>

<to-view-id>/index.xhtml</to-view-id>

<redirect />

</navigation-case>

</navigation-rule>

<navigation-rule>

<description>Regra de navegação para sessões inexistentes

</description>

<from-view-id>/*</from-view-id>

<navigation-case>

<from-outcome>sessao_invalida</from-outcome>

<to-view-id>/index.xhtml</to-view-id>

<redirect />

</navigation-case>

</navigation-rule>

<lifecycle>

<phase-listener>br.com.devmedia.javamagazine.controller.

ListenerAutenticacao</phase-listener>

</lifecycle>

</faces-config>

O controle de permissão de acesso

Uma vez cobertos todos os conceitos relevantes sobre sessões de usuário, vamos partir agora para a

configuração de um modelo de controle de acesso a funcionalidades de acordo com perfis pré-estabelecidos.

De acordo com a Tabela 1 já apresentada, temos três perfis de acesso pré-configurados no banco de dados.

Estes perfis serão utilizados para, em tempo de execução, configurar o perfil de acesso do usuário “logado”.

Para isto, o projeto contém uma classe chamada ControladorAcesso, que pode ser observada na Listagem

6. Se voltarmos para a Listagem 2, notaremos que existe uma instância desta classe mantida pelo bean

gerenciado responsável pelas atividades de login e logout. Para o controle de acesso propriamente dito,

foram criados três atributos booleanos que são valorados de acordo com a natureza do usuário que realizou o

login. Observe, novamente, a Tabela 2, e verá que existe uma coluna na tabela de usuários, chamada “tipo”,

que guarda exatamente o nível de permissão de acesso associado a cada usuário.

Listagem 6. O controlador de acesso da aplicação.

Page 17: JSF - Controle de Sessões e Controle de Acesso.pdf

/**

* Controlador utilizado especificamente para verificação de permissões de

* acesso a funcionalidades oferecidas pela aplicação.

*/

public class ControladorAcesso {

private boolean permissaoAdministrador;

private boolean permissaoFuncionario;

private boolean permissaoComum;

public boolean isPermissaoAdministrador() {

HttpSession sessao = (HttpSession)

FacesContext.getCurrentInstance().getExternalContext().

getSession(true);

Usuario usuarioSessao = (Usuario) sessao.getAttribute

(MbLogin.USUARIO_SESSAO);

if (usuarioSessao != null) {

permissaoAdministrador = (usuarioSessao.getTipo() ==

Usuario.ADMINISTRADOR);

} else {

permissaoAdministrador = false;

}

return permissaoAdministrador;

}

public boolean isPermissaoFuncionario() {

HttpSession sessao = (HttpSession)

FacesContext.getCurrentInstance().getExternalContext().

getSession(true);

Usuario usuarioSessao = (Usuario) sessao.getAttribute

(MbLogin.USUARIO_SESSAO);

if (usuarioSessao != null) {

permissaoAdministrador = (usuarioSessao.getTipo() ==

Usuario.ADMINISTRADOR);

if (permissaoAdministrador) {

permissaoFuncionario = true;

} else {

permissaoFuncionario = (usuarioSessao.getTipo() ==

Usuario.FUNCIONARIO);

}

} else {

permissaoFuncionario = false;

}

return permissaoFuncionario;

}

Page 18: JSF - Controle de Sessões e Controle de Acesso.pdf

public boolean isPermissaoComum() {

HttpSession sessao = (HttpSession)

FacesContext.getCurrentInstance().getExternalContext().

getSession(true);

Usuario usuarioSessao = (Usuario) sessao.getAttribute

(MbLogin.USUARIO_SESSAO);

if (usuarioSessao != null) {

permissaoAdministrador = (usuarioSessao.getTipo() ==

Usuario.ADMINISTRADOR);

permissaoFuncionario = (usuarioSessao.getTipo() ==

Usuario.FUNCIONARIO);

if (permissaoAdministrador || permissaoFuncionario) {

permissaoComum = true;

} else {

permissaoComum = (usuarioSessao.getTipo() ==

Usuario.CONVIDADO);

}

} else {

permissaoComum = false;

}

return permissaoComum;

}

/**

* Método utilizado para configurar o perfil de acesso do usuário logado às

* funcionalidades da aplicação.

*/

public void configurarAcesso() {

HttpSession sessao = (HttpSession)

FacesContext.getCurrentInstance().getExternalContext().getSession(true);

Usuario usuarioSessao = (Usuario) sessao.getAttribute

(MbLogin.USUARIO_SESSAO);

if (usuarioSessao != null) {

Logger.getLogger("ControladorAcesso").log(Level.INFO,

">>>>>>>>>>>>>> Usuário da sessão tem tipo {0}",

usuarioSessao.getTipo());

permissaoAdministrador = (usuarioSessao.getTipo() ==

Usuario.ADMINISTRADOR);

if (permissaoAdministrador) {

permissaoFuncionario = true;

} else {

Page 19: JSF - Controle de Sessões e Controle de Acesso.pdf

permissaoFuncionario = (usuarioSessao.getTipo() ==

Usuario.FUNCIONARIO);

permissaoComum = (usuarioSessao.getTipo() ==

Usuario.CONVIDADO);

}

}

}

}

Já sabemos que, assim que a operação de login for realizada com sucesso, será guardada na sessão uma

instância da classe br.com.devmedia.javamagazine.domain.Usuario, representando o usuário que está

acessando o sistema. Deste modo, sempre que necessário, a aplicação determinará o nível de permissão de

acesso às suas funcionalidades de acordo com esta instância. A lógica desta unidade de controle utilizará as

premissas listadas a seguir para determinar o nível de acesso às funcionalidades:

· Se o nível do usuário for CONVIDADO, apenas o atributo booleano permissaoComum será valorado em

true;

· Se o nível de usuário for FUNCIONÁRIO, os atributos booleanos permissaoComum e

permissaoFuncionario serão valorados em true.

· Se o nível de usuário for ADMINISTRADOR, todos os três atributos booleanos

(permissaoAdministrador, permissaoFuncionario e permissaoComum) serão valoradas em true.

Esses atributos foram definidos como booleanos para que o recurso de renderização de componentes do

PrimeFaces possa ser aproveitado. Existe uma propriedade, comum a todo componente visual do

PrimeFaces, chamado rendered. Quando definido em true, que é o valor padrão para esta propriedade, a

máquina de renderização trabalhará no desenho deste componente. Caso contrário, este componente será

escondido, e a página se ajustará para exibir apenas os demais itens, classificados como “renderizáveis”.

Para exemplificar este recurso, vamos analisar duas páginas do sistema: uma delas contém funcionalidades

que são visíveis apenas a funcionários e outras visíveis apenas para administradores, e a segunda página é o

template já apresentado na Listagem 3. Iniciaremos pelo template. Se voltarmos a esta listagem,

verificaremos que a página de administração (admin.xhtml) tem a sua apresentação controlada a partir desta

propriedade, rendered, da seguinte maneira:

rendered="#{mbLogin.controladorAcesso.permissaoFuncionario}"

Já a página de administração, cujo conteúdo se encontra na Listagem 7, é dividida em duas partes: uma de

visualização de dados de pacotes de viagem e outra de cadastro de novos pacotes. Enquanto a visualização

de pacotes é permitida tanto a funcionários comuns quanto a administradores, somente estes últimos poderão

visualizar e manipular a seção de cadastro de novos pacotes. Esta configuração é feita da seguinte maneira:

rendered="#{mbLogin.controladorAcesso.permissaoAdministrador}"

Desta maneira, podemos filtrar quais funcionalidades estarão visíveis a cada tipo de usuário, e todo o

controle é realizado programaticamente, eventualmente envolvendo sistemas de informação como bancos de

dados, dependendo sempre da solução em questão.

O sistema, que estará disponível para download através do portal da DevMedia, contém outros exemplos de

controle de acesso e alguns trechos adicionais envolvendo o controle de sessões, dando a oportunidade do

leitor de explorar um pouco mais cada um desses recursos.

Listagem 7. Página destinada a funcionários e administradores da aplicação.

Page 20: JSF - Controle de Sessões e Controle de Acesso.pdf

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://java.sun.com/jsf/html"

xmlns:f="http://java.sun.com/jsf/core"

xmlns:p="http://primefaces.org/ui"

xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head>

<title>#{messages.PRAIAS_TITULO}</title>

</h:head>

<h:body>

<h:form>

<ui:composition template="templates/template.xhtml">

<ui:define name="page_content">

<p:accordionPanel>

<p:tab title="#{messages.ADMIN_ACCORDION_TITULO_PRECOS}">

<h:panelGrid columns="1" cellpadding="10">

<p:dataTable id="tabelaPrecos" var="diaria"

value="#{mbAluguel.diariasReferencia}"

paginator="true" rows="10" rowsPerPageTemplate="5,10,15"

paginatorTemplate="{CurrentPageReport} {FirstPageLink}

{PreviousPageLink} {PageLinks} {NextPageLink}

{LastPageLink}

{RowsPerPageDropdown}" >

<f:facet name="header">

#{messages.ADMIN_ACCORDION_TITULO_PRECOS}

</f:facet>

<p:column>

<f:facet name="header">

<h:outputText

value="#{messages.ADMIN_TABELA_COLUNA_MES_REFERENCIA}" />

</f:facet>

<h:outputText value="#{diaria.mesReferencia}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText

value="#{messages.ADMIN_TABELA_COLUNA_ANO_REFERENCIA}" />

</f:facet>

<h:outputText value="#{diaria.anoReferencia}" />

Page 21: JSF - Controle de Sessões e Controle de Acesso.pdf

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="#{messages.ADMIN_TABELA_COLUNA_DIARIA}" />

</f:facet>

<h:outputText value="#{diaria.valor}" />

</p:column>

</p:dataTable>

</h:panelGrid>

</p:tab>

<p:tab title="#{messages.ADMIN_ACCORDION_TITULO_PACOTES}">

<h:panelGrid columns="1" cellpadding="10">

<p:dataTable id="tabelaPacotes" var="pacote"

value="#{mbAluguel.pacotes}"

paginator="true" rows="10" rowsPerPageTemplate="5,10,15"

paginatorTemplate="{CurrentPageReport} {FirstPageLink}

{PreviousPageLink} {PageLinks} {NextPageLink}

{LastPageLink}

{RowsPerPageDropdown}" >

<f:facet name="header">

#{messages.ADMIN_TABELA_PACOTES_2013}

</f:facet>

<p:column>

<f:facet name="header">

<h:outputText value="#{messages.ADMIN_PACOTE_NOME}" />

</f:facet>

<h:outputText value="#{pacote.nome}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="#{messages.ADMIN_PACOTE_DESCRICAO}" />

</f:facet>

<h:outputText value="#{pacote.descricao}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="#{messages.ADMIN_PACOTE_DATA_INICIO}" />

</f:facet>

<h:outputText value="#{pacote.dataInicio}" />

</p:column>

Page 22: JSF - Controle de Sessões e Controle de Acesso.pdf

<p:column>

<f:facet name="header">

<h:outputText value="#{messages.ADMIN_PACOTE_DATA_TERMINO}" />

</f:facet>

<h:outputText value="#{pacote.dataFim}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="#{messages.ADMIN_PACOTE_VALOR}" />

</f:facet>

<h:outputText value="#{pacote.valorFechado}" />

</p:column>

</p:dataTable>

<!-- Formulário para cadastro de novos pacotes -->

<h:outputLabel value="#{messages.ADMIN_PACOTE_CADASTRO_TITULO}"

style="color: darkolivegreen; font-size: 1.7em;

font-weight: bold;"

rendered="#

{mbLogin.controladorAcesso.permissaoAdministrador}" />

<p:spacer rendered="#

{mbLogin.controladorAcesso.permissaoAdministrador}" />

<p:panel

rendered="#{mbLogin.controladorAcesso.permissaoAdministrador}">

<p:panelGrid columns="2">

<h:outputLabel value="#{messages.ADMIN_PACOTE_NOME}"

style="color:darkgreen; font-weight: bold;" />

<p:inputText value="#{mbAluguel.pacoteCadastro.nome}" size="40"

/>

<h:outputLabel value="#{messages.ADMIN_PACOTE_DATA_INICIO}"

style="color:darkgreen; font-weight: bold;" />

<p:calendar value="#{mbAluguel.pacoteCadastro.dataInicio}"

id="pacoteDataInicio" showOn="button" />

<h:outputLabel value="#{messages.ADMIN_PACOTE_DATA_TERMINO}"

style="color:darkgreen; font-weight: bold;" />

<p:calendar value="#{mbAluguel.pacoteCadastro.dataFim}"

id="pacoteDataFim" showOn="button" />

<h:outputLabel value="#{messages.ADMIN_PACOTE_VALOR}"

style="color:darkgreen; font-weight: bold;" />

<p:inputText value="#{mbAluguel.valorPacoteAvaliacao}"

size="40" maxlength="15" id="parcela" />

Page 23: JSF - Controle de Sessões e Controle de Acesso.pdf

<h:outputLabel value="#{messages.ADMIN_PACOTE_DESCRICAO}"

style="color:darkgreen; font-weight: bold;" />

<p:inputText value="#{mbAluguel.pacoteCadastro.descricao}"

size="40" />

</p:panelGrid>

<p:commandButton value="#{messages.ADMIN_PACOTE_ACAO_SALVAR}"

ajax="false" action="#{mbAluguel.salvarPacote()}"

update="tabelaPacotes" />

</p:panel>

</h:panelGrid>

</p:tab>

</p:accordionPanel>

</ui:define>

</ui:composition>

</h:form>

</h:body>

</html>

Conclusão

Ao longo do artigo, exploramos os recursos de controle de sessões e permissões de acesso usando apenas a

especificação Java EE e, mais especificamente, JavaServer Faces com foco em sua implementação mais

popular, o PrimeFaces.

Como podemos observar, os recursos apresentados são facilmente aplicáveis, cabendo ao desenvolvedor

apenas a missão de desenhar uma estratégia consistente para refleti-la, depois, em uma implementação

adequada.

Embora existam inúmeras tecnologias capazes de nos trazer um alto nível de segurança no mercado,

principalmente associadas à plataforma Java, é importante que sempre pensemos em uma combinação que

nos traga, mais que facilidade, boa resposta final. Como falamos no início do artigo, existem combinações

muito populares no cenário de desenvolvimento de sistemas web que são, normalmente, rotuladas como

modelos obrigatórios, imprescindíveis, para a entrega de boas soluções.

Entretanto, é sempre importante observar que, ao adicionarmos mais e mais frameworks em um desenho de

sistema web, estamos também adicionando overhead na comunicação entre esses componentes e, também,

uma demanda por profissionais gabaritados em todas essas tecnologias, em alto nível suficiente para

responder com rapidez e alta qualidade no suporte a sistemas que atendem, normalmente, grandes empresas.

A especificação Java EE vem evoluindo bastante, e é importante que desenvolvedores Java para a web

conheçam muito bem cada um dos recursos disponíveis na implementação (Java EE mais genericamente e

Mojarra/MyFaces/PrimeFaces no tocante à especificação JSF). Servlets 3.0 e CDI são tópicos que todo leitor

e amante do Java devem, desde já, procurar conhecer melhor, pois são bem interessantes e trazem uma

facilidade no trabalho com esta plataforma.

Além do que já está disponível para o desenvolvedor, temos também boas promessas definidas para a versão

7 e recursos potencialmente interessantes planejados para as especificações do Java 8 e Java 9, dentre os

quais se destaca o já polêmico projeto Jigsaw. Empregar recursos da própria especificação Java será sempre

um bom negócio, e muitos deles ainda são muito pouco conhecidos e explorados pela grande maioria dos

desenvolvedores.

Page 24: JSF - Controle de Sessões e Controle de Acesso.pdf