Spring Security
Aplicações web, assim como qualquer aplicação que trabalhe com dados privados, necessitam de áreas privadas para que apenas usuários autorizados tenham acesso a esses dados. Para obter essa restrição em aplicações que rodam em servidores na internet, existem várias formas e hoje iremos demonstrar como implementar isso utilizando o Spring Security.
Essa ferramenta é mantida pela SpringSource, que também é responsável pelo framework web Spring. Nesse artigo, iremos demonstrar como incorporar essa solução em um projeto WEB juntamente com o framework VRaptor. Vale lembrar que esse tutorial demonstra apenas uma configuração básica de como utilizar essa ferramenta. Caso ele não se encaixe bem nas suas necessidades ou você tenha interesse em se aprofundar no assunto, recomendo que passe no site da SpringSource e estude de forma mais aprofundada os recursos do Spring Security.
Base de dados
A base de dados é bem simples, contendo apenas duas tabelas. A tabela regra(rule) armazena os “tipos” de acesso que serão interpretados pelo Spring Security. Nesse que estamos demonstrando, cada usuário terá apenas uma regra, mas nada impede de você adaptar a base e a configuração do projeto para que os usuários tenham múltiplas regras.
Projeto WEB
Abaixo segue a estrutura do projeto WEB que irá utilizar VRaptor e Spring Security.
Bibliotecas Spring Security
Na imagem acima, estão destacados apenas os arquivos necessários à implementação do Spring Security. Alguns são comuns ao VRaptor também, mas mesmo esses estão destacados por causa da versão utilizada. Os demais arquivos não destacados são a biblioteca padrão para projetos VRaptor.
Configuração web.xml
No arquivo web.xml, temos que adicionar um listener e um filter para que o Spring Security intercepte as requisições feitas. Note que, na ordem de declarações, os dados do Spring Security vêm antes do VRaptor. Essa ordem é muito importante, pois se for invertida, o filtro do VRaptor irá interceptar primeiro as requisições e irá concluí-las sem que sejam validadas pelas regras do Spring Security.
<?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>Aplicação Exemplo Spring Security</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>
<filter>
<filter-name>vraptor</filter-name>
<filter-class>br.com.caelum.vraptor.VRaptor</filter-class>
</filter>
<filter-mapping>
<filter-name>vraptor</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
</web-app>
Configuração Spring Security
Abaixo segue parte do arquivo applicationContext.xml. Ele é o responsável por configurar os parâmetros do Spring Security. O arquivo completo está disponível para download no final do post.
Basicamente o que este arquivo contém é uma tag responsável por interceptar as requisições http e aplicar as regras de validação conforme forem configuradas. Nesse caso, configuramos que o path “/” irá conter o formulário de login e também é de acesso livre. Já tudo que estiver a partir do path “/admin” irá ser filtrado e uma sessão autenticada com a rule ROLE_ADMIN será exigida.
Para iniciar essa sessão com o usuário, o formulário de login irá utilizar os parâmetros setados na tag para buscar os dados de usuário na base de dados e assim validar os dados informados. Ele fará isso através de duas queries SQL. A primeira busca o usuário e valida sua senha. Já a segunda busca as regras de acesso para o usuário em questão. Como você pode ver no XML, dentro da TAG adaptamos os comandos SQL para buscar os dados nas tabelas ‘usuario’ e ‘regra’, modificando os nomes das colunas para o padrão reconhecido pelo Spring Security.
<http auto-config="true">
<form-login login-page="/" authentication-failure-url="/?error=invalido" default-target-url="/admin"/>
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
</http>
<authentication-manager>
<authentication-provider>
<password-encoder hash="md5" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT email as username, senha as password, 'true' as enable FROM usuario WHERE email = ?"
authorities-by-username-query="SELECT u.email as username, r.nome as authority FROM usuario u, regra r WHERE u.regra_id = r.id AND email = ?"/>
</authentication-provider>
</authentication-manager>
Nesse exemplo as senhas estão sendo encriptadas com MD5. Se você não quiser encriar a senha, basta mudar o hash para plaintext.
Classe para encriptar senhas usando MD5:
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.authentication.encoding.PasswordEncoder;
public class EncriptarMD5 {
public static String encriptar(String senha) {
PasswordEncoder encoder = new Md5PasswordEncoder();
senha = encoder.encodePassword(senha, null);
return senha;
}
}
Controllers Login e Admin
Para testarmos a segurança da área privada da aplicação, vamos precisar de uma área com acesso livre, que será a área de login, e uma área privada, que será chamada de admin.
Para a área liberada vamos criar o controller Login e a página index.jsp, a qual irá incorporar o formulário de login. Vale lembrar que esse controller não será o responsável pelo login, sua função é apenas redirecionar para a página que irá conter o formulário. O formulário irá disparar a requisição de login para o Spring Security, que validará os dados e se encarregará de encaminhar a requisição para a página adequada. Lembre-se de que o formulário da página index.jsp demonstrada abaixo deve conter o padrão de nomes conforme foi informado. O mesmo vale para a URL responsável pelo encerramento da sessão contida no arquivo /admin/index.jsp. O Spring Security só irá interpretar os dados se eles forem enviados dessa forma.
LoginController.java
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Resource;
@Resource
public class LoginController {
@Path("/")
public void index() {
}
}
/login/index.jsp
<!-- Bem lembrado pelo Lucas Cavalcanti. A verificação de msg de erro pode ser com <c:if>-->
<c:if test="${param.error eq 'invalido'}">
<c:out value="Usuário e/ou senha inválido(s)">
</c:if>
<form name="f" action="<c:url value="/j_spring_security_check"/>" method="POST">
<table>
<tr>
<td>
<c:out value="Usuário:"/>
</td>
<td>
<input type='text' name='j_username'/>
</td>
</tr>
<tr>
<td>
<c:out value="Usuário:"/>
</td>
<td>
<input type='password' name='j_password'>
</td>
</tr>
<tr>
<td colspan='2'>
<input name="submit" type="submit">
</td>
</tr>
<tr>
<td colspan='2'>
<input name="reset" type="reset">
</td>
</tr>
</table>
</form>
AdminController.java
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Resource;
import java.security.Principal;
import javax.servlet.http.HttpServletRequest;
@Resource
public class AdminController {
//Adicionamos o request no construtor para obter os dados do usuário logado
private HttpServletRequest request;
public AdminController(HttpServletRequest request) {
this.request = request;
}
@Path("/admin")
public void index() {
Principal user = request.getUserPrincipal(); //Aqui o usuário logado é obtido
System.out.println(user.getName()); // getName() retorna o e-mail do usuário
}
}
/admin/index.jsp
<body>
<c:out value="Painel Admin - Sessão iniciada"/><br/>
<a href="<c:url value="/j_spring_security_logout"/>">Logout</a>
</body>
Captura das telas
- Arquivos do post: Download
- Projeto completo: Download
- O projeto foi criado na IDE Eclipse e executado no container servlet Tomcat 6







Gostaria de saber como mostrar o nome do usuario logado ?
obrigado 1
Daniel, primeiramente tenho que lhe parabenizar pelo ótimo trabalho em apresentar o Spring Security e aproveito para lhe solicitar o link para download deste projeto (Security), já que no link disponível até o momento estão os JAR´s, SQL´s e o XML de configuração.
Eu tenho acompanhado tuas mensagens no fórum GUJ e aqui no teu blog, sendo assim, gostaria de lhe sugerir um artigo sobre o Spring LDAP, ou uma implementação de Spring LDAP em conjunto deste artigo.
Obrigado e parabéns.
Opa, você pode fazer assim:
Authentication user = SecurityContextHolder.getContext().getAuthentication();
Desse objetouser você consegue pegar o login e a senha.
[]‘s
Daniel
Obrigado Dennys.
Acabei de disponibilizar o projeto completo para download.
Sobre o Spring LDAP, realmente é uma boa idéia. Vou preparar um post sobre isso sim. Valeu pela dica.
[]‘s
Daniel
Velinho gostei bastante do exemplo, gostaria de implantar os VRaptor & SPring Security , ams em todos os meus projetos usamos Hibernate e Criptografia interna, por isso ou teriamos de ter ou
, sabe como posso resolver isso???
Queria usar as tags:
&alt;authentication-provider user-service-ref=’customUserDetailsService’ &glt;
&alt;password-encoder ref=”customPasswordEncoder” /&glt;
ótimo post parabéns Daniel,
Eu sempre tive uma dúvida com relação ao spring security é possível controllar o login por usuário ou seja usuario X logou em maquina Y, e logou novamente em maquina W, automaticamente invalidar o login de Y ?
sei que aqui não é um forum de discussão mas você me ajudaria bastante se me mostrasse como fazer.
Obrigado.
Gostaria de parabenizar por este post maravilhoso. Estou me formando em Ciência da Computação e estou querendo fazer a monografia com o tema: Segurança em Aplicações Web Utilizando o Framework Spring Security. Teria algum livro para me indicar? No aguardo…
Mas, como limitar usuários por sessão ?
Ou seja … Se um usuário está logado com um login e senha e outro tentar logar com o mesmo login e senha retornar
uma mensagem relatando que já existe alguém logado com aquela senha ?
É possível ?
Pessoal quando eu tento fazer o logout com
<a href="”>Logout
da erro 404 alguem tem uma ideia do que pode ser?
Daniel,
Parabéns pelo post. Ele está otimo.
Quero criar um sistema multiempresa onde, no formulário de login, além do “usuário” e “senha”, gostaria de informar a empresa que está sendo logada através de um selectItem e passá-la para a sessão para poder pegá-la quando necessário.
Você tem um exemplo de como fazer isso?
Sampaio.
Estou fazendo um teste, e estava procurando justamente esta integração vou tentar seguir seus passos.
Valeu.
Então Márcio, acho que para tratar isso você teria que criar um filter para interceptar todas as novas sessões e armazená-las. Dessa forma, no momento em que o usuário for inserido (no momento do login) você poderá verificar se existe alguma outra sessão com o mesmo usuário. Caso existe, a mais antiga pode ser invalidada.
Obrigado Sampaio. Esse tipo de controle eu acho que é melhor fazer utilizando um @Component com escopo de sessão. Nele você poderá colocar a empresa ativa e outros dados. No site do VRaptor tem uma boa documentação sobre eles (http://caelum.github.com/vraptor/docs/componentes/). E como é um @Component, você pode recebê-lo diretamente nos construtores dos Controllers.