Spring Security, Spring JPA e o JAVAEE

Quando pensamos em adicionar a parte de segurança dentro da nossa aplicação, a primeira solução que vem a nossa cabeça é usar o Spring Security. Por sinal é um pensamento que faz todo sentido, já que hoje em dia ele é o projeto de segurança mais completo do mercado. Só que quando estamos no mundo JAVAEE, já existe uma especificação responsável por essa área, a JAAS. Colocando as duas lado a lado, não é complexo perceber que o Spring Security é uma solução bem mais moderna, com uma arquitetura mais bem bolada e com pontos de extensões mais definidos. Além disso é muito mais sincronizado com a realidade da maioria dos projetos. Queremos fazer segurança baseada em roles urls e ter uma maneira fácil de fazer essa associação é um grande diferencial. Este post é para você, que está numa aplicação JAVAEE, mas tem o desejo de usar o Spring Security como framework de segurança. Vou assumir que o leitor já sabe o básico do framework.

A configuração inicial não muda muito, supondo que você usa Maven, é necessário adicionar as novas dependências no pom.xml. 

		<!-- spring -->

		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>4.0.1.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>4.0.1.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>4.1.0.RELEASE</version>
		</dependency>

O primeiro ponto diferente é em relação a configuração do filtro. Normalmente basta que você declare uma classe que herde AbstractSecurityWebApplicationInitializer e pronto. Só que como não estamos usando nada além do Spring, precisamos mudar um pouco código e passar todas as nossas classes de configuração que devem ser carregadas.

   public class SpringSecurityFilterConfiguration extends
		AbstractSecurityWebApplicationInitializer {

	public SpringSecurityFilterConfiguration() {
		super(SecurityConfiguration.class,SystemUserDAO.class,JPAConfiguration.class);
	}
   }

Geralmente você não precisa fazer isso, porque este passo já foi realizado na classe de configuração do Spring MVC. A classe SecurityConfiguration não tem nada demais, você pode acessá-la seguindo o link. Ela basicamente define as regras de segurança, da mesma forma que seria feito em um projeto usando unicamente a stack do Spring. A classe SystemUserDAO também não tem nada demais, ela implementa a interface UserDetailsService e precisa de um EntityManager injetado. E agora sim, temos uma situação. Qual EntityManager deve ser injetado? Lembre que estamos dentro de um servidor de aplicação e o melhor que usemos o contexto de persistência provido pelo container. Para a nossa sorte, o Spring é bastante extensível e não tem a menor pretensão de ser apenas usado isolado de todo mundo.

Como já temos um persistence.xml configurado, integrado com a JTA e utilizando o DataSource configurado no servidor, precisamos apenas ensinar ao Spring que queremos tirar proveito de todas essa configuração. Para isso vamos dar uma olhada na classe JPAConfiguration.

	package br.com.casadocodigo.security;

	//imports

	import org.springframework.context.annotation.Bean;

	public class JPAConfiguration {

		@Bean
		public EntityManagerFactory emf() throws NamingException {
			Context ctx = new InitialContext();
			EntityManagerFactory lookup = (EntityManagerFactory) ctx
					.lookup("java:comp/env/persistence/casadocodigo-emf");
			return lookup;
		}
	}

Simplesmente buscamos a referência para a EntityManagerFactory a partir da JNDI. Uma especificação muito usada no mundo Java, onde conseguimos associar nomes a objetos que podem ser recuperados no servidor. Uma pergunta que pode estar na sua mente é: de onde veio esse nome? Para isso vamos usar outro recurso da especificação JAVAEE, nesse caso a de Servlets. Conseguimos expor a EntityManagerFactory na JNDI, a partir do nosso arquivo web.xml.

	<persistence-unit-ref>
		<persistence-unit-ref-name>persistence/casadocodigo-emf</persistence-unit-ref-name>
		<persistence-unit-name>casadocodigo-persistence-unit</persistence-unit-name>
	</persistence-unit-ref>

A tag persistence-unit-ref-name define o nome que você quer expor na JNDI. Já a tag persistence-unit-name faz referência ao nome configurado no arquivo web.xml.

Pronto! Dessa forma conseguimos adicionar o Spring Security por exemplo, em um projeto usando JSF dentro de um servidor JAVAEE. Aproveitamos as configurações da JPA já feitas pela aplicação e simplesmente escrevemos a ponte para o Spring. Uma outra pergunta que pode ficar na cabeça é: o servidor JAVAEE já tem o CDI, só que o Spring faz a  mesma coisa. Não tem problema algum, não estamos querendo colocar o Spring para ser o controlador da Injeção de Dependências do sistema, estamos apenas usando o necessário para o Spring Security funcionar. Outra detalhe bem interessante é que a parte principal do Spring Security funciona dentro de um Filterpor isso conseguimos usar ele para fazer a segurança de qualquer aplicação web.

O Spring foi pensado justamente para ser extensível. É claro que o melhor dos mundos é usar os módulos do próprio Spring e ser feliz, mas isso nem sempre é possível. Também não fique preso ao estigma de usar Spring ou JAVAEE, use o que se encaixe melhor na sua aplicação. Encare tudo como ferramenta, nada de nutrir amor por tecnologia :).

4 thoughts on “Spring Security, Spring JPA e o JAVAEE

  1. Aproveitando o assunto sobre Spring Security. Gostaria que me recomendasse a melhor forma de aplicar restrição de acesso aos elementos dá página. Por exemplo. Imagine que eu tenha um cadastro onde apenas alguns campos podem ser exibidos para certo usuário. Ou seja a restrição não é por página, não depende da action. Como eu esconderia uma por exemplo ?
    Já passou por problema parecido ?
    Abraços.

    Like

  2. Oi Alberto.
    Eu li o seu artigo (http://blog.caelum.com.br/revisitando-a-batalha-spring-x-java-ee-em-detalhes/) e um trecho me chamou a atenção:

    “Possível uso das plataformas em conjunto

    Essa é uma daquelas coisas que muitas vezes são rechaçadas na arquitetura do projeto. Não existe nenhuma regra do mundo que te faça optar por um caminho e, obrigatoriamente, ter que abandonar o outro. Por exemplo, o Spring Security é completamente baseado em Servlet Filter, o que faz com que ele seja plugável em qualquer aplicação web Java que rode sobre um Servlet Container. Só que você vai ficar limitado a proteger só as suas URLs, pois os beans estarão sendo gerenciados pelo CDI/EJB.”

    Minha pergunta é sobre o seguinte trecho: Só que você vai ficar limitado a proteger só as suas URLs, pois os beans estarão sendo gerenciados pelo CDI/EJB.
    O que significa proteger só as URLs?

    Valeu

    Like

Leave a comment