Você está na página 1de 18

Spring Security 3 Jpa 2 e JSF 2

O Spring Security uma alternativa segurana oferecida pela especificao Java EE. O framework
centraliza as configuraes em um nico XML, dispensando configuraes do container, tornando a
aplicao web portvel.
Assim, todo o controle passa a ser feito de maneira declarativa, e na prtica isso significa retirar do
desenvolvedor a responsabilidade de ter que controlar o acesso a recursos por perfis de maneira
programtica, utilizando filtros, por exemplo.

Aplicativos web so formados por diversos recursos, como pginas dinmicas, estticas, imagens,
downloads, uploads, formulrios, relatrios, etc. Na maioria delas existe a necessidade de controlar o
acesso dos usurios a estes recursos, restringindo-o somente para aqueles previamente identificados e
autenticados. Portanto, toda aplicao, em especial as aplicaes web, deve apresentar maneiras de
alocar ou retirar permisses de seus usurios, atravs de mecanismos de controle de acesso como
autenticao e autorizao.
O Spring Security 3 um framework que tem como objetivo auxiliar na autenticao e autorizao dos
usurios das aplicaes. uma ferramenta simples de ser utilizada, porm, na integrao com JSF 2,
necessrio alguns cuidados que sero apresentados neste artigo. O framework surgiu da necessidade de
uma biblioteca de segurana Java robusta e adaptvel a diversos tipos de situaes. Apesar de existirem
ferramentas como o Java Authentication and Authorization Service (JAAS) e o Java EE Security, a
tecnologia da Spring Source uma opo diferenciada que prov um conjunto de funcionalidades de fcil
uso, alm de fornecer apoio para integrao com vrios outros sistemas de autenticao que podem j
existir na empresa ou ser de sua necessidade.
Neste contexto, o objetivo desse artigo ser, a partir de uma abordagem prtica, apresentar o
funcionamento do Spring Security, bem como mostrar a integrao com JSF e JPA. Ao final, o leitor
estar apto a construir aplicaes web seguras utilizando essas tecnologias.

Autenticao X Autorizao
Antes de entender como a segurana do Spring funciona, fundamental conhecer dois conceitos:
autenticao e autorizao. Esses conceitos j foram amplamente discutidos nas edies 87 e 88 da
revista, portanto caso o leitor j esteja familiarizado com eles, poder simplesmente passar para o
prximo tpico. No entanto, apresentamos abaixo no apenas os conceitos, mas tambm a relao deles
com o framework Spring Security.
Autenticao
A autenticao a verificao das credenciais (nome de usurio e senha) da tentativa de conexo. Esse
processo consiste no envio de credenciais do cliente para o servidor em um formulrio de texto simples
ou criptografado usando um protocolo de autenticao.
Como veremos mais adiante, o Spring Security possui vrias formas de realizar a autenticao.
Podemos utilizar, por exemplo, o formulrio de login que gerado automaticamente pelo framework ou

construir o nosso prprio formulrio personalizado. Os usurios da aplicao que sero autenticados
podem ser definidos diretamente no arquivo XML de configuraes do framework ou em um banco de
dados, como veremos neste artigo.
Autorizao
Autorizao utilizada para verificar se determinado usurio previamente autenticado possui permisso
para usar, manipular ou executar o recurso em questo. a concesso de uso para determinados tipos
de servio, dada a um usurio previamente autenticado.
O Spring Security possui uma abordagem declarativa para a segurana, baseada em roles (papis). Por
exemplo, uma aplicao de uma pousada poderia ter dois roles: um ADMIN, que possui permisso para
cadastrar acomodaes e reserv-las, e um COMUM, que possui permisso apenas para reserv-las.
Dessa forma os usurios que forem utilizar essa aplicao teriam que possuir algum desses roles.

Criando uma aplicao segura com Spring Security 3,


JSF 2 (PrimeFaces) e JPA 2
Para demonstrar o funcionamento do Spring Security, bem como a integrao com o JSF e JPA, vamos
criar uma aplicao web simples. Para esse exemplo foi utilizado a IDE Eclipse Indigo, banco de dados
MySQL 5 e Tomcat 7 como servidor de aplicao. Sendo que o leitor poder utilizar outro banco de
dados, IDE ou servidor de aplicao de sua preferncia.
Construindo as tabelas
O primeiro passo deve ser a criao das tabelas necessrias para autenticao e autorizao no banco
de dados, bem como a insero de alguns dados para teste.
Para criar estas tabelas no seu banco de dados MySQL, execute atravs de um script o cdigo presente
na Listagem 1. Este cdigo, alm de criar o schema e gerar as tabelas, insere trs usurios para que seja
possvel realizarmos testes posteriormente.
O controle de acesso do framework baseado em roles. Os roles ou papis, em portugus, nos ajudam
a gerenciar as autorizaes que um determinado usurio tem dentro de uma aplicao. Esses roles nos
permitem customizar o acesso a recursos da aplicao ou at mesmo da pgina.
Para nosso exemplo, utilizamos trs tabelas para efetuar o controle de acesso da nossa aplicao, so
elas: user, role e user_role.
A tabela user responsvel por guardar o login (username) e senha (password) do usurio. A tabela role
guarda os papis (roles) do sistema. E por fim a tabela user_role associa cada usurio do sistema a seu
respectivo papel. Vale ressaltar que cada usurio pode estar associado a um ou mais roles, dando assim
uma maior flexibilidade.
Imagine a seguinte situao: voc tem uma aplicao web que possui uma pgina que lista os usurios
do sistema. Porm, somente os usurios com o role ADMIN podem excluir informaes dessa pgina.
Na mesma aplicao existe um menu que d acesso ao relatrio de vendas do ms, mais somente quem
SUPERVISOR pode executar esse relatrio. Dessa forma, um usurio que tem permisso tanto de
excluir os usurios como executar o relatrio de vendas deve estar associado aos roles ADMIN e
SUPERVISOR.

Entendendo a estrutura do projeto


Veja na Figura 1 como ficou a estrutura do projeto. No se preocupe de no entender exatamente o
que faz cada arquivo, pois nas prximas sesses iremos explicar mais detalhes sobre cada arquivo do
projeto. O projeto completo, bem como as bibliotecas necessrias esto disponveis para download entre
os arquivos dessa edio no site da Java Magazine.
Configurando o web.xml
O diretrio WEB-INF possui o arquivo web.xml, que o Deployment Descriptor da aplicao. Ele contm
informaes de configuraes como parmetros de inicializao, mapeamento de Servlets entre outros.
Para facilitar o entendimento o web.xml foi dividido em vrias partes separadas por comentrios, como
apresentado na Listagem 2. Na primeira parte temos a configurao do Spring 3, onde informamos
que as configuraes referentes ao Spring estaro localizadas no arquivo root-context.xml. Depois
mapeamos um listener (ContextLoaderListener) que responsvel por inicializar o contexto do Spring na
aplicao. Esse contexto ser utilizado pelo Spring para fabricar beans, injetar as dependncias, publicar
eventos, entre outros.
Em seguida apresentamos as configuraes necessrias para o JSF, incluindo o servlet Faces Servlet,
que ser responsvel pelas renderizaes feitas pelo JSF. Na sequncia configuramos o Prime Faces,

que a implementao do JSF 2 que decidimos usar para esse exemplo. Finalmente, descrevemos um
filtro HTTP para interceptar todas as URLs acessadas e conferir suas permisses de acesso. Por isso, o
filtro aplicado com o url-pattern /*.
Configurando o faces-config.xml
Dentro do diretrio WEB-INF (veja a Figura 1) encontramos tambm o arquivo faces-config.xml, que o
arquivo principal de configurao de uma aplicao JSF. Ele responsvel por descrever os elementos e
sub-elementos que compem o projeto, tais como as regras de navegao, os beans gerenciados,
validadores, conversores, entre outros. Antes de continuarmos, veja como ficou a estrutura do nosso
faces-config.xml na Listagem 3. Nele configuramos as nossas regras de navegao e registramos o
ELResolver do Spring fazendo a integrao com JSF.

Configuraes do Spring
As configuraes do Spring so muito extensas e se dividem em configuraes gerais, do banco de
dados e de segurana. Assim sendo, uma boa prtica dividi-las em mais de um arquivo, deixando um

arquivo para cada tipo de configurao. No nosso exemplo, as dividimos em trs arquivos, conforme
mostrado na Figura

1, mais precisamente, no diretrio spring.


O primeiro deles, o arquivo root-context.xml (Listagem 4) o mais simples. Nele informamos na tag

<context:component-scan> o atributo base-package com o pacote comum a todas as classes do sistema.


Assim o Spring consegue detectar automaticamente essas classes e registrar os beans correspondentes.
O atributo base-package tambm aceita uma lista de pacotes separada por vrgula, que pode ser til caso
no deseje informar um pacote comum para todas as classes. Nas demais linhas, simplesmente
importamos os outros dois arquivos de configurao.

No arquivo db.xml, apresentado na Listagem 5, mapeamos as informaes do banco de dados:


usurio, senha, url e driver para que o Spring crie e gerencie o dataSource. Para o nosso exemplo
estamos utilizando as configuraes do MySQL. Caso deseje, altere essas configuraes para o banco de
dados de sua preferncia.
O ltimo e mais importante arquivo dos arquivos de configuraes do Spring o applicationContextsecurity.xml, apresentado na Listagem 6. Nesse arquivo criamos as regras de segurana da
aplicao.
A tag <http> a tag root de todas as configuraes de segurana da aplicao. O seu atributo useexpressions marcado como true habilita o uso de EL-expressions no atributo access da tag <intercepturl>. J o atributo auto-config marcado com true configura o framework para utilizar autenticao HTTPBasic, cria um formulrio de login de autenticao padro e configura o logout. Para o nosso exemplo
estamos usando a tag <form-login>, onde criamos um formulrio de login personalizado, logo o formulrio
padro no gerado.
A tag <intercept-url> usada para determinar o conjunto de padres de URL que a aplicao est
interessada em controlar o acesso e a respectiva restrio. O atributo pattern descreve o caminho que
ser feito o controle e o atributo access define a restrio.

Para o nosso exemplo podemos ler esta tag da seguinte forma: todas as pginas que estiverem dentro da
pasta pages s sero acessadas por usurios autenticados. As demais pginas estaro disponveis para
qualquer usurio.
O objetivo da tag <form-login> configurar o caminho da pgina de login (atributo login-page), bem
como a pgina que o usurio ser redirecionado caso a login falhe (atributo authentication-failure-url).
Usando a tag <access-denied-handler> mapeamos a pgina que ser exibida quando um usurio tentar
acessar um recurso o qual no tenha autorizao.
Por fim, na tag <authentication-manager> definimos que o authentication-provider que o Spring Security
ir executar vai ser o userDetailsService. Explicaremos este recurso em mais detalhes quando formos
falar sobre o processo de autenticao.

Executando o exemplo
Deste modo terminamos as configuraes estruturais da aplicao que consistiram em criar as tabelas,
criar o projeto e configurar os arquivos XML para integrar o Spring, Spring Security, JSF, PrimeFaces e
JPA. Agora vamos rodar a aplicao e entender como o Spring Security realiza a autenticao e
autorizao da nossa aplicao. Para esse exemplo usamos o Tomcat 7 como servidor de aplicao,
porm, se desejar, voc pode usar outro servidor de sua preferencia.
Ao acessar a aplicao (http://localhost:8080/spring-jsf-jpa/) a primeira pgina que ser exibida a
home.xhtml (Figura 2). Como essa pgina est fora da pasta pages, ela pode ser acessada por todos
os usurios aplicao, at mesmo os que no estejam logados. Essa regra foi definida no arquivo
applicationContext-security.xml (Listagem

6).

A Listagem 7 apresenta a pgina home.xhtml onde temos o link aqui que redireciona a aplicao
para uma rea restrita (/pages/menu.xhtml).
Dessa forma, ao clicar nesse link o usurio automaticamente redirecionado para a pgina de login
(Figura 3), j que o usurio ainda no est logado. Veja que essa uma pgina de login personalizada.
Ela foi construda utilizando PrimeFaces 3 e bem diferente da pgina de login padro fornecida pelo
framework.

Entendendo o processo de autenticao


A pgina login.xhtml, mostrada na Listagem 8, contm o formulrio com os campos userName e
password que armazenaro as credenciais do usurio. Esses dados sero submetidos para a classe
LoginBean quando o usurio clicar no boto Ok. A classe LoginBean pode ser vista na Listagem 9.
Essa classe responsvel por receber o pedido de autenticao e verificar se as credenciais do usurio
so vlidas. Para realizar esse processo ela invoca o mtodo login() do componente
AuthenticationService.
Conforme pode ser observado na Listagem 10, o componente AuthenticationService que
registramos na aplicao, cria o objeto token do tipo UsernamePasswordAuthenticationToken, que uma
classe do prprio framework responsvel por armazenar o login (userName) e a senha (password) do
usurio. Em seguida invoca o mtodo authenticate() do componente do Spring AuthenticationManager.
O AuthenticationManager ir chamar a nossa implementao de UserDetailsService, conforme foi
definido no arquivo de configurao do Spring Security, e esta ser responsvel por buscar o usurio pelo
userName, como pode ser visto na Listagem

11.

Listagem 10. AuthenticationService.java - Responsvel pelo login e logout da


aplicao.
package br.com.springsecurity.service;
// imports omitidos...
@Component
public class AuthenticationService {
@Autowired
@Qualifier("authenticationManager")
private AuthenticationManager authenticationManager;
public boolean login(String username, String password) {
try {
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken
(username,password);
Authentication authenticate = authenticationManager.
authenticate(token);
if (authenticate.isAuthenticated()) {
SecurityContextHolder.getContext().
setAuthentication(authenticate);
return true;
}
}
catch (AuthenticationException e) {}
return false;
}

public void logout() {


SecurityContextHolder.getContext().setAuthentication(null);
invalidateSession();
}
public User getUsuarioLogado() {
return (User) SecurityContextHolder.getContext().
getAuthentication().getPrincipal();
}

private void invalidateSession() {

FacesContext fc = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) fc.getExternalContext().getSession(false);
session.invalidate();

O componente UserDetailsServiceImpl implementa o mtodo loadUserByUsername() da interface


UserDetailsService do Spring. Esse mtodo utiliza o EntityManager (gerenciador de entidades da JPA) e
executa uma consulta que verifica se existe no banco de dados da aplicao um usurio com o userName
informado. Caso no seja encontrado um usurio no banco de dados, ser disparada uma exceo
(UsernameNotFoundException), o framework interrompe o fluxo de autenticao e redireciona o usurio
para a pgina de erro (que no nosso caso a prpria pgina de login). Se existir um usurio com o
userName informado, esse usurio devolvido como retorno do mtodo e o framework ir verificar se o
password foi informado corretamente.

Caso positivo o Spring Security autentica o usurio e o adiciona no contexto de segurana do Spring
(SecurityContext).

Entidades
Para o nosso exemplo criamos duas entidades que representam o controle de acesso da aplicao, so
elas: User e Role. Esse um modelo bem tpico em aplicaes web, e caso o leitor deseje, poder
adicionar outros atributos ou mtodos nessas classes. Para que o Spring consiga gerenciar o usurio e
efetuar o controle de acesso, a entidade User, exibida naListagem

12, deve implementar a interface

isAccountNonExpired() - indica se a conta do usurio expirou. Uma conta expirada no pode ser
autenticada;
isAccountNonLocked() - informa se o usurio est bloqueado ou desbloqueado. Um usurio bloqueado
no pode ser autenticado;
isCredentialsNonExpired() - mostra se as credenciais do usurio (password) expiraram. Se o password
tiver expirado, o usurio no pode ser autenticado;
isEnabled() - indica se o usurio est ativado ou desativado. Um usurio desativado no pode ser
autenticado.
Para os mtodos isAccountNonExpired(), isAccountNonLocked(), isCredentialsNonExpired() e
isEnabled(), simplesmente retornamos true, j que no nos interessa ter esse controle nesse exemplo.
Nos mtodos getPassword() e getUsername() retornamos, respectivamente, a senha e o login do usurio.
Por fim, no mtodo getAuthorities() construmos uma lista de autorizaes (GrantedAuthority) de acordo
com os Roles que o usurio possui. Conforme observado da Listagem 14, a entidade Role
representa as permisses ou papis do usurio no sistema.UserDetails do String, mostrada
na Listagem 13.
A interface UserDetails apresenta os seguintes mtodos:
getAuthorities() - retorna as permisses concedidas ao usurio. usado pelo framework para realizar o
processo de autorizao;
getPassword() - retorna o password usado para autenticar o usurio;
getUsername() - retorna o username usado para autenticar o usurio;

Listagem 14. Role.java - Representa os papis dos usurios na


aplicao.
package br.com.springsecurity.model;
// imports omitidos...
@Entity
public class Role implements Serializable {
private static final long serialVersionUID = 5886820991361556707L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotNull
@Size(min = 3, max = 60)
private String name;
...
}

Testando a autorizao
Como voc j conhece o processo de autenticao, podemos testar a autorizao. Na tela de login,
exibida na Figura

3, entre com o usurio admin e senha 123. Ao efetuar o login voc ser

redirecionado para o home da aplicao (Figura 2). Em seguida clique no link aqui para acessar o
menu da aplicao. Note que como voc j est autenticado voc ser redirecionado para a pgina
menu.xhtml (Figura 4). Veja que os menus Cadastro e Segurana esto sendo exibidos, pois estamos
autenticados com um usurio que possui o role ADMIN. Esse controle de autorizao em nvel de pgina

s possvel devido taglib sec do Spring Security, que importamos (http://www.springframework.org/


security/facelets/tags) na pgina menu.xhtml, conforme podemos ver na Listagem

15.

Essa tag utilizada para mostrar/esconder informaes (juntamente com o atributo rendered das tags
JSF) de acordo com as permisses (roles) do usurio logado. Ela possui trs atributos: ifAllGranted,
ifAnyGranted e ifNotGranted. Todos eles suportam um ou mais roles separados por vrgula. O atributo
ifAllGranted informa que o usurio tem que possuir todos os roles declarados para retornar true e assim
renderizar o contedo. O atributo ifAnyGranted necessita de apenas um dos roles para retornar true, e o
atributo ifNotGranted ser true apenas se o usurio no possuir nenhum dos roles.
Veja na Listagem 15 que utilizamos apenas ifAnyGranted dentro do atributo rendered da tag
<p:submenu> para dar as permisses de acesso ao menu do sistema. Isso significa que se o usurio
possuir qualquer um dos roles: ADMIN, SUPERVISOR ou COMUM, ter acesso ao menu Cadastro da
aplicao.
Por fim, ainda na pgina menu.xhtml, clique no link Logout e acesse a aplicao com o login comum e
senha 123. Veja que agora s aparece o menu Cadastro.

O menu Relatrio no foi renderizado porque este usurio s possui o role COMUM.

Concluses
Este artigo demonstrou como simples realizar a integrao do Spring Security 3, JavaServer Faces 2,
PrimeFaces 3 e JPA 2 para construir aplicaes web seguras. O leitor pode utilizar esse tutorial como
base para aplicar uma poltica de segurana mais complexa em suas aplicaes.
O Spring Security se mostrou um framework de fcil utilizao, pois trabalha com uma abordagem
declarativa para as configuraes de segurana, baseada no conceito de roles (papis). Atravs da
segurana declarativa, possvel habilitar a segurana por meio de configuraes na aplicao, o que
evita alteraes no cdigo. Dessa forma no necessrio chamar nenhum mtodo para realizar
autorizao de acesso a usurios em um sistema. Depois de definir os roles basta informarmos
aplicao quais recursos podem ser visualizados por um usurio que acessou uma rea restrita.

Uma outra vantagem de utilizar esse framework a portabilidade. Quando utilizamos a API de segurana
que o Java EE prov, fica difcil portar a aplicao, pois esta fica dependente de um servidor de aplicao
especfico. Diferentemente do Spring Security, que cria uma camada de abstrao da API de segurana,
tornando a aplicao portvel para qualquer servidor Java EE.