Olá, tudo bom? Como vão vocês?
Este artigo é o primeiro de uma série que falaremos sobre segurança em aplicações Java, começando com a primeira parte do artigo sobre Spring Security. Dúvidas e críticas são bem vindas.
Segurança de dados através do Spring Security
A segurança de áreas restritas em aplicações Web escritas em Java não é uma tarefa das mais triviais.
Sabendo que não era simples criar áreas de segurança, em 2003 surge o Acegi Security System for Spring, um framework extremamente configurável e complexo. Comum na época, suas configurações eram baseadas em XML e demorava um tempo para que o desenvolvedor o dominasse completamente.
O projeto Acegi evoluiu e, em 2007, foi incorporado aos projetos do Spring Framework, sendo renomeado para Spring Security.
A versão 2.0 foi lançada em 2008 e em 2010 a versão 3.0, a que iremos utilizar neste artigo.
Download do Framework
Para trabalhar com o Spring Security, você deve realizar o download no endereço http://www.springsource.org/download. No momento em que este artigo é escrito, a versão utilizada é a Spring Security 3.0.2. Clique em Download.
Baixe a versão spring-security-3.0.2.RELEASE.zip. Ao baixar, descompacte o arquivo extraindo todos os JARs existentes no diretório lib.
Também será preciso baixar o Spring Framework. No momento em que este artigo é escrito, a versão utilizada é a Spring Framework 3.0.2.
Como o Spring Security trabalha
Da mesma forma que faríamos se estivéssemos utilizando JAAS, o Spring Security trabalha a segurança através de declarações baseadas em papéis (roles). Seja em XML ou Anotações, o Spring Security não necessita chamar método algum para realizar uma autenticação ou autorização.
Através dos roles definidos, podemos informar ao aplicativo em questão, ao qual está sendo assegurada uma área, quais recursos podem ser acessados ou restringidos a uma determinada pessoa que acessou a área restrita.
Preparando o ambiente de trabalho
Para este artigo, iremos utilizar a IDE da Spring Source, divisão da VMware, criada sobre a plataforma Eclipse, chamada de SpringSource Tools Suite.
Para baixar o SpringSource Tools Suite, clique aqui, preencha o formulário e faça o Download. Como a ferramenta possui uma opção de instalador, use-a como facilitador se desejar. Na própria página onde baixar o arquivo, haverá a explicação da instalação em cada plataforma, em Installation Instructions.
Criando um projeto
No SpringSource Tools Suite, clique no menu File>New>Dynamic Web Project. Na caixa de diálogo New Dynamic Web Project, digite ProjSpringSecurity (ou o nome que desejar) em Project name.
O SpringSource Tools Suite possui embutido um servidor de aplicações Java Web baseado no Apache Tomcat 6, só que com algumas modificações. Entretanto, vamos utilizar o Tomcat, que pode ser adicionado como mostro neste artigo.
Confirme a criação do projeto no botão Finish.
Adicionando as bibliotecas ao Projeto
Com o direito do mouse sobre o projeto, na view Project Explorer, vá até Properties. Na caixa de diálogo das propriedades do projeto, vá até Java EE Module Dependencies. Clique em Add External JARs e adicione os seguintes arquivos:
- org.springframework.aop-3.0.2.RELEASE.jar
- org.springframework.asm-3.0.2.RELEASE.jar
- org.springframework.beans-3.0.2.RELEASE.jar
- org.springframework.context-3.0.2.RELEASE.jar
- org.springframework.core-3.0.2.RELEASE.jar
- org.springframework.expression-3.0.2.RELEASE.jar
- org.springframework.transaction-3.0.2.RELEASE.jar
- org.springframework.web-3.0.2.RELEASE.jar
- spring-security-config-3.0.2.RELEASE.jar
- spring-security-core-3.0.2.RELEASE.jar
- spring-security-taglibs-3.0.2.RELEASE.jar
- spring-security-web-3.0.2.RELEASE.jar
- commons-logging-1.1.1.jar
Note que o 13º item é um JAR que não pertence a família do Spring Framework. Você pode baixar o arquivo compactado, contendo a biblioteca commons-logging-1.1.1.jar, clicando aqui.
Uma aplicação simples com Spring Security
Para exemplificar como funciona o Spring Security, vamos criar uma aplicação simples com apenas uma área segura. Esta área segura será representada dentro de um diretório, chamado admin.
Teremos duas páginas index.jsp: uma na raiz do aplicativo e outra dentro do diretório admin, como mostra a Figura 5.
As páginas JSP
A página index.jsp, existente dentro do diretório admin exibe apenas uma mensagem simples, como mostra a Figura 6, com apenas HTML.
O conteúdo é mostrado na Listagem 1.
Listagem 1 – O conteúdo HTML da página /admin/index.jsp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Usuário Logado</title> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> </head> <body> <h2>Parabéns, você está logado!</h2> </body> </html>
A página index.jsp encontrada na raiz exibe apenas um link que o leva até a área administrativa. Sua aparência é idêntica a Figura 7.
O conteúdo da página index.jsp encontrada na raiz da aplicação é mostrado na Listagem 2.
Listagem 2 – O conteúdo HTML da página /index.jsp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Página Inicial</title> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> </head> <body> <h2>Uma aplicação simples com Spring Security</h2> <hr /> <a href="admin">Clique aqui para acessar a área administrativa</a> </body> </html>
Configurando o web.xml
Para que o Spring Security, assim como o Spring, precisamos configurar o web.xml. O Spring Security utiliza um filtro HTTP para interceptar as URLs acessadas e verificar as permissões de acesso.
A Listagem 3 exibe a configuração do arquivo web.xml.
Listagem 3 – O arquivo web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>ProjSpringSecurity</display-name> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
Para configurar o Spring Security, utilizamos o filtro org.springframework.web.filter.DelegatingFilterProxy, devidamente configurado na Listagem 3. O filtro está sendo aplicado em todo o aplicativo, podendo ser visto no elemento <url-pattern />.
Atenção: Um detalhe importante que precisa ser notado é o nome do filtro, colocado no elemento <filter-name/>. Não o altere, pois o Spring já espera pelo nome springSecurityFilterChain.
Configurando o applicationContext.xml
O Spring Security será configurado no arquivo applicationContext.xml. Este arquivo deverá ser criado dentro do diretório WEB-INF, com o conteúdo mostrado na Listagem 4.
Listagem 4 – O arquivo applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"> <http auto-config="true"> <intercept-url pattern="/admin/**" access="ROLE_ADMIN" /> </http> <authentication-manager> <authentication-provider> <user-service> <user name="edson" password="integrator" authorities="ROLE_ADMIN" /> </user-service> </authentication-provider> </authentication-manager> </beans:beans>
No Spring Security, as configurações de autenticação e autorização estão sendo feitas no arquivo de contexto padrão do Spring (applicationContext.xml). Para que este arquivo seja lido, adicionamos no web.xml o elemento <listener />, contendo o listener org.springframework.web.context.ContextLoaderListener.
O listener do Spring faz com que as configurações sejam carregadas na inicialização da aplicação Web.
Ao ser carregado pelo listener, o arquivo da Listagem 4 declara os usuários e suas regras de acesso ao aplicativo.
O controle de acesso é feito pelo elemento <http />, do applicationContext.xml. Este controle é definido no sub-elemento <intercept-url />. O atributo pattern, de <intercept-url />, informa, através de uma expressão, em qual local o filtro deve agir, bem como define a sua regra de acesso, através do atributo access.
Para que possamos definir que qualquer elemento dentro do diretório admin fique acessível somente para os usuários do role ROLE_ADMIN, adicionamos uma expressão comum no Apache Ant.
Caso tenhamos mais de um sub-elemento <intercept-url />, teremos sua interpretação sendo feita por ordem de definição, sendo que, a primeira que atender a regra, será chamada. Na prática, isto significa que, se houver /admin/relatorios/** e /admin/**, o primeiro caso deverá ser lido primeiro, portanto será o primeiro a ser adicionado na ordem em applicationContext.xml.
O atributo auto-config, com o valor true, indica a configuração automática da aplicação para utilizar um formulário de login. O JSP do formulário é gerado automaticamente pelo Spring Security neste caso. A Figura 8 exibe o formulário gerado pelo Spring Security.
Com o atributo <authentication-manager>, gerenciamos os usuários e seus respectivos roles que darão permissão ao diretório especificado anteriormente, em <intercept-url />, pelo filtro.
Para facilitar a compreensão do exemplo, adicionamos apenas um usuário, através de <user/>, informando o nome de usuário, a senha e o seu papel de acesso.
Ao logar no aplicativo, o Spring analisará qual role é permitido no diretório e quem possui tal permissão.
Personalizando o formulário de acesso a área restrita
É interessante ter uma geração automática de formulário no Spring Security, ajuda a testar a codificação, com certeza. Mas não é agradável ao aplicativo como um todo, pois sempre precisamos criar o formulário com as características gerais desenvolvidas no layout das páginas.
Criando a página personalizada de login
Para isso, o Spring Security nos fornece a personalização do formulário. A Listagem 5 exibe o conteúdo da página /login.jsp que ficará na raiz do seu aplicativo, junto com index.jsp.
Listagem 5 – A página login.jsp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Área Restrita</title> </head> <body> <h2>Área Restrita</h2> <hr /> <% if(request.getParameter("error") != null){ if (request.getParameter("error").equals("invalido")){ %> <p> <span style="color:red"> Usuário ou Senha inválidos </span> </p> <% } //fim do if equals }//fim do if null %> <form action="j_spring_security_check" method="post"> Usuário: <input name="j_username" type="text" value="${not empty login_error ? SPRING_SECURITY_LAST_USERNAME : ''}" /> <br /> Senha: <input type="password" name="j_password"><br /> <input type="submit" value="Efetuar Login"><br /> <a href="index.jsp">Retornar para a Página Inicial</a> </form> </body> </html>
Para que o formulário funcione com o Spring Security, as regras mais básicas são:
- O atributo action deve apontar para j_spring_security_check;
- O atributo name da caixa de entrada de texto, do nome de usuário, deve ser j_username;
- O atributo name da caixa de entrada de senha deve ser j_ password.
Estes princípios básicos farão com que seu formulário funcione com o Spring Security. Entretanto, precisamos mostrar uma mensagem de erro, caso o usuário não tenha colocado as informações necessárias ou, as mesmas não sejam compatíveis com o registrado no sistema para permitir a entrada na área restrita.
É exatamente o papel do if(request.getParameter(“error”) e if (request.getParameter(“error”).equals(“invalido”)), na página login.jsp, personalizado, com um parâmetro que iremos transmitir, através do Spring Security, caso ocorra um erro na permissão.
A página personalizada pode ser vista na Figura 9.
Alterando o arquivo applicationContext.xml
Por fim, mas não menos importante, precisamos alterar o arquivo applicationContext.xml para que o Spring Security passe a trabalhar com a página de login personalizada que criamos. A seguir você tem o trecho, contendo o elemento <form-login/>, que deve ser inserido por entre o elemento <http />:
<form-login login-page=“/login.jsp” authentication-failure-url=“/login.jsp?error=invalido”/>
O elemento <form-login/> é de simples compreensão, pois temos atributos que descrevem bem sua função:
login-page: A página personalizada com o formulário de substituição do padrão existente no framework
authentication-failure-url: URL de retorno caso ocorra um erro. Note que adicionamos, após “?” , error=invalido. Isto demonstra, claramente, que não é uma regra fixa o que pode ser transmitido, caso ocorra um erro, na entrada de uma determinada área restrita.
No próximo artigo sobre Spring Security
Embora tenhamos conhecido os elementos básicos de utilização do Spring Security, restou colocar o acesso ao banco de dados para fazer uma autenticação verdadeira, como ocorre em sistemas.
No próximo artigo veremos como fazer para trabalhar com Spring Security e o acesso ao banco de dados, com um exemplo completo, passo a passo.
Até o próximo artigo pessoALL.
abril 25th, 2010 9:24
opa! Edson,
Realmente excelente post, e bem didático parabens!!
abracos,
abril 25th, 2010 12:17
@Camilo,
Obrigado amigo!
abril 27th, 2010 15:13
Muito bom! Aguardaremos!
maio 10th, 2010 11:59
[…] This post was mentioned on Twitter by valdir m. s. junior. valdir m. s. junior said: Segurança de dados através do Spring Security http://bit.ly/bePZo1 […]
junho 3rd, 2010 19:17
Oi, gostaria de saber se pode me ajudar com o seguinte Problema:
No meu sistema o usuário e o administrador têm áreas restritas diferentes, gostaria que após o login eles fosse redirecionados para as suas respectivas áreas.
junho 4th, 2010 8:16
@Rafael,
É possível, claro. Mas não é um assunto de rápida explicação. Eu diria que é interessante pesquisar mais sobre o modo de trabalho do Spring Security, para obter todas as características que precisa, de modo que o filtro gerado em sua aplicação direcione seu usuário ao local onde é necessário acessar.
julho 8th, 2010 6:36
Esse desgraçado em 1 post, falou o que eu le em 600 páginas em ingles… filha da mae do cara[…].. bom pra po[…]…
SUPER PARABÉNS..
juniorsatanas
julho 8th, 2010 6:38
Vou comprar todos os livros desse cara.. agora sei que vale .. cada real..
juniorsatanas
julho 8th, 2010 14:12
@juniorsatanas
Desculpe a edição, mas infelizmente não dava para deixar os palavrões, ok?
Valeu por comentar.
julho 20th, 2010 11:45
Olá Edson…
você não falou
“# O atributo name da caixa de entrada de texto, do nome de usuário, deve ser j_username;
# O atributo name da caixa de entrada de senha deve ser j_ password.”
No código de exemplo os inputs estão sem os names..
eu dei um Ctrl c +ctrl v e depois que vi q estava errado.
Gostei do artigo,
Pena que o Spring Security 3.0 com banco de dados não deu certo quando eu configuro o
..form-login login-page=”/login.jsp” authentication-failure-url=”/login.jsp?error=invalido”/>
você pode conferir se o código do artigo está correto e depois me da um toque?
Vlws
julho 20th, 2010 14:56
@Raquel,
Muito bem observado o erro. Ao colar do meu editor de textos para o blog, o editor do WordPress comeu algumas tags e adicionou outras. Na minha edição, não reparei que havia removido estas informações. Obrigado por corrigir o erro e está corrigido no blog também.
Quanto ao seu erro do Spring Security com banco de dados, verifique se não deixou algo para trás ou que erro é apresentado na saída do seu servidor de aplicações.
Grato,
agosto 6th, 2010 10:56
[…] Spring Security Sem BD […]
agosto 12th, 2010 7:31
[…] Spring Security Sem BD […]
outubro 20th, 2010 22:21
[…] Spring Security Sem BD […]
outubro 29th, 2010 15:36
Mto bom o artigo…Parabéns!!!
Eu fiz o exemplo funcionou certinho…mas tenho uma dúvida
Edson vc poderia me explicar que código eu devo acrescentar ai no exemplo para que o usuario após efetuar o logout não consiga voltar para a pagina onde estava logado atraves back (voltar do navegador)?
Pq eu logo no sistema, ai faço o logout….mas qndo eu clico em voltar pelo navegador ele volta para a pagina logada, onde o correto seria direcionar novamente para a pagina de login correto?
Obrigado
outubro 31st, 2010 7:06
@Caio,
O “back” ou “voltar” do navegador é um evento client. Portanto, o código que deve incluir não operaria no servidor.
Você pode usar desde meta tags até JavaScript para forçar o navegador e ler o estado atual da sessão.
Entretanto, saiba que, mesmo o usuário retornando no navegador, para um estado anterior, ao começar a clicar nos links, ele será jogado ao login e senha,pois o navegador não possui mais a sessão aberta.
janeiro 6th, 2011 18:08
Olá Edson! Primeiramente parabéns por suas postagens, muito boas… direto caio no seu blog quando estou procurando alguma coisa de JEE hehehe
A algumas semanas comecei a mexer com autenticação no meu projeto, segui todos os seus passos e funcionou perfeitamente! Porém, no meu caso eu preciso ter um selectOneMenu de filiais no form de login.. tipo assim, quando o usuario vai acessar o sistema, ele precisa selecionar a qual filial ele pertente(ele pode pertencer a mais de uma filial) … aí vem o detalhe, eu tenho um bean que implementa o Authentication do Spring Security e que faz a autenticação, até aí funciona… mas eu preciso pegar o codigo da filial selecionada nesse bean, mas ele só me retorna null! vc sabe se é possivel fazer isso nem que seja de outra forma? Grata pela atenção! 🙂
janeiro 8th, 2011 2:35
@andii,
Você pode usar o JSF PhaseListener para armazenar esta filial para que não se perca após a autenticação.
janeiro 8th, 2011 11:11
Olá Edson… depois de muito ler a doc do Spring Security, acabei descobrindo um metodo na classe UsernamePasswordAuthenticationFilter, aí eu implemento ela e faço a minha autenticação. Obrigada! Agora o meu problema está sendo mandar uma mensagem para a tag h:message … quando faço FacesContext.addMessage(…) dá nullpointer… :S
maio 8th, 2011 23:31
Olá.
Gostei muito do artigo, estava tendo muitas dificuldades para implementar um sistema de login no meu projeto usando interceptors do struts 2, na verdade eu consegui implementar, mas não definir diferentes níveis de usuário.
Dai me deparo co Spring que resolve tudo de uma forma muito mais prática. Muito Obrigado mesmo!
Estou indo agora ler a segunda parte do Tutorial.
setembro 10th, 2011 4:07
Parabéns, Edson, muito bom esse seu passo a passo com Spring Security
março 2nd, 2012 10:13
Parabéns pelo post Edson, bastante esclarecedor pra quem está começando a usar o spring-security… bem tenho uma dúvida sobre como usar os facelets do spring-security.. quero saber como renderizar ou não um menu qualquer de acordo com o tipo de usuário que está fazendo login, Ao mais seu post ja me ajudou bastante!
Parabéns
março 14th, 2012 10:02
Perfeito o Artigo Edson.
Resta-me algumas pequenas dúvidas.
1º)
Você utilizou a IDE Spring Source, mas, posso continuar utilizando o NetBeans? Interfere em algo?
2º)
Trabalho em uma empresa que tem o sistema desktop e está sendo reestruturado para uma versão web utilizando jsf. Há alguma restrição na implementação?
No mais, parabéns e muito sucesso.
Estarei sempre acompanhando seu blog e aprendendo novas soluções.
março 18th, 2012 1:33
@Max,
Pode usar qualquer ferramenta, seja o Eclipse ou NetBeans. O importante é seguir as regras de configurações do framework que não terá problemas e nem restrições na implementação.
Bons códigos!
abril 10th, 2012 23:38
@Lucas,
Caso ainda não tenha resolvido, deixarei aqui em aberto para que algum leitor possa responder, caso tenham tempo.
setembro 3rd, 2012 9:08
Pessoal, só uma ressalva, eu fiz o exemplo do jeito que está ai,porém, me apareceu um erro de NoClassDefFoundError e consegui resolver adicionando o “jar org.springframework.jdbc-3.1.2.RELEASE” que vem no download .zip do Spring Framework.
dezembro 20th, 2012 23:08
Parabéns, muito bom…
O conteúdo do seu site é ótimo
março 8th, 2016 21:22
Você me ajudou muito!!! Obrigado. Site save favoritos!