Exemplo de Login e Logout do Spring 4 Security MVC

Hoje vamos aprender sobre o Exemplo de Login com Spring Security. Antes de ler este post, por favor, dê uma olhada no meu post anterior em “Introdução ao Spring 4 Security” para entender alguns conceitos básicos.

Exemplo de Login e Logout com Spring Security

Neste post, vamos desenvolver uma Aplicação Web de Segurança Spring 4 MVC para fornecer recursos de Login e Logout usando a opção In-Memory. Este exemplo utiliza a Configuração Java do Spring com Anotações do Spring, ou seja, sem usar web.xml e Configuração XML do Spring (Estilo Antigo). Se você não está familiarizado com o Módulo de Segurança do Spring 3.x, por favor, leia os seguintes posts primeiro para entender a Receita de Segurança do Spring.

  1. Exemplo de Segurança Spring MVC usando autenticação em memória, UserDetailsService e JDBC
  2. Segurança Spring em Aplicações Web Servlet usando autenticação DAO, JDBC, em memória

O Módulo de Segurança do Spring 4 suporta as seguintes opções para armazenar e gerenciar Credenciais de Usuário:

  1. Armazenamento em Memória
  2. Bancos de Dados Relacionais (RDBMS)
  3. Armazenamento de Dados No SQL
  4. LDAP

Vamos usar a opção “Armazenamento em Memória” neste exemplo. Discutiremos outras opções em meus próximos posts. Vamos utilizar o Spring 4.0.2.RELEASE, Spring STS 3.7 Suite IDE, Spring TC Server 3.1 com Java 1.8 e a ferramenta de construção Maven para desenvolver este exemplo.

Exemplo de Login do Spring Security

Vamos desenvolver uma lógica de Login e Logout usando os Recursos de Segurança do Spring 4. O principal objetivo desta aplicação é desenvolver uma aplicação sem usar o “web.xml” e sem escrever uma única linha de Configuração de Feijões XML do Spring. Isso significa que vamos usar o recurso de Configuração Java do Spring com Anotações Spring. Vamos desenvolver esta aplicação com as seguintes características:

  1. Página de Boas-Vindas
  2. Página de Login
  3. Página Inicial
  4. Recurso de Logout

Por favor, siga os seguintes passos para desenvolver e explorar este Exemplo Simples de Login do Spring 4 Security.

  • Crie um Projeto “Maven Web Spring Simples” no Spring STS Suite com os seguintes detalhes
   Project Name : SpringMVCSecruityMavenApp
  • Atualize o pom.xml com o seguinte conteúdo
<?xml version="1.0" encoding="UTF-8"?>
<project
   xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 
   https://maven.apache.org/xsd/maven-4.0.0.xsd"
   xmlns="https://maven.apache.org/POM/4.0.0" 
   xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">

	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev</groupId>
	<artifactId>SpringMVCSecruityMavenApp</artifactId>
	<packaging>war</packaging>
	<version>1.0</version>

	<properties>
	    <java.version>1.8</java.version>
	    <spring.version>4.0.2.RELEASE</spring.version>
	    <spring.security.version>4.0.2.RELEASE</spring.security.version>
	    <servlet.api.version>3.1.0</servlet.api.version>
	    <jsp.api.version>2.2</jsp.api.version>
	    <jstl.version>1.2</jstl.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${spring.security.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${spring.security.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servlet.api.version}</version>
		</dependency>		
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>${jsp.api.version}</version>
		</dependency>
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>
	</dependencies>	

	<build>
	    <finalName>SpringMVCSecruityMavenApp</finalName>
	    <plugins>
		<plugin>
		     <groupId>org.apache.maven.plugins</groupId>
		     <artifactId>maven-compiler-plugin</artifactId>
		     <version>3.1</version>
		     <configuration>
			<source>${java.version}</source>
			<target>${java.version}</target>
		     </configuration>
		</plugin>
		<plugin>
	           <groupId>org.apache.maven.plugins</groupId>
	           <artifactId>maven-war-plugin</artifactId>
	           <configuration>
	              <failOnMissingWebXml>false</failOnMissingWebXml>
	           </configuration>           
        	</plugin>
	    </plugins>
	</build>
</project>

NOTA:- Se você não está ciente da flag “<failOnMissingWebXml>”, por favor, leia no final deste post para obter uma boa compreensão do uso deste elemento.- Primeiro, desenvolva o Controlador de Login usando a anotação @Controller do Spring.
LoginController.java

package com.journaldev.spring.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class LoginController {

	@RequestMapping(value = { "/"}, method = RequestMethod.GET)
	public ModelAndView welcomePage() {
		ModelAndView model = new ModelAndView();
		model.setViewName("welcomePage");
		return model;
	}

	@RequestMapping(value = { "/homePage"}, method = RequestMethod.GET)
	public ModelAndView homePage() {
		ModelAndView model = new ModelAndView();
		model.setViewName("homePage");
		return model;
	}
	
	@RequestMapping(value = "/loginPage", method = RequestMethod.GET)
	public ModelAndView loginPage(@RequestParam(value = "error",required = false) String error,
	@RequestParam(value = "logout",	required = false) String logout) {
		
		ModelAndView model = new ModelAndView();
		if (error != null) {
			model.addObject("error", "Invalid Credentials provided.");
		}

		if (logout != null) {
			model.addObject("message", "Logged out from JournalDEV successfully.");
		}

		model.setViewName("loginPage");
		return model;
	}

}

Explicação do Código:- Definimos três métodos no “LoginController” para lidar com três tipos diferentes de solicitações de cliente

  1. welcomePage() irá lidar com todas as solicitações de cliente que estão usando o URI “/”.
  2. homePage() irá lidar com todas as solicitações de cliente que estão usando o URI “/homePage”.
  3. loginPage() irá lidar com todas as solicitações de cliente que estão usando o URI “/loginPage”.
  4. Na loginPage(), nós cuidamos de lidar com mensagens de erro e logout.
  • Em seguida, desenvolva uma classe “LoginSecurityConfig” para fornecer recursos de Segurança de Login e Logout usando a API de Segurança do Spring 4.
    LoginSecurityConfig.java
package com.journaldev.spring.secuity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder authenticationMgr) throws Exception {
		authenticationMgr.inMemoryAuthentication()
			.withUser("journaldev")
			.password("jd@123")
			.authorities("ROLE_USER");
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
			.antMatchers("/homePage").access("hasRole('ROLE_USER')")
			.and()
				.formLogin().loginPage("/loginPage")
				.defaultSuccessUrl("/homePage")
				.failureUrl("/loginPage?error")
				.usernameParameter("username").passwordParameter("password")				
			.and()
				.logout().logoutSuccessUrl("/loginPage?logout"); 
		
	}
}

Explicação do Código:- Definimos dois métodos em “LoginSecurityConfig” para armazenar e gerenciar Credenciais do Usuário e cuidar dos recursos de Segurança de Login e Logout.

  1. @EnableWebSecurity A anotação é usada para habilitar a segurança na web em qualquer aplicativo web.
  2. A anotação @EnableWebMVCSecurity é usada para habilitar a segurança na web em uma aplicação web baseada em Spring MVC.

    NOTA:- @EnableWebSecurity = @EnableWebMVCSecurity + Recursos extras. É por isso que a anotação @EnableWebMVCSecurity está obsoleta no Framework Spring 4.x.

    A classe “LoginSecurityConfig” ou qualquer classe designada para configurar a Segurança do Spring deve estender a classe “WebSecurityConfigurerAdapter” ou implementar a interface relacionada.

  3. O método configureGlobal() é usado para armazenar e gerenciar credenciais de usuário.
  4. No método configureGlobal(), podemos usar o método authorities() para definir os papéis da nossa aplicação, como “ROLE_USER”. Também podemos usar o método roles() para o mesmo propósito.
  5. Diferença entre os métodos authorities() e roles():
  6. O método authorities() precisa de um nome de papel completo como “ROLE_USER”, enquanto o método roles() precisa de um nome de papel como “USER”. Ele automaticamente adicionará o valor “ROLE_” a este nome de papel “USER”. NOTA:- Desenvolveremos outro exemplo para demonstrar papéis como “USER”, “ADMIN” em minhas próximas postagens.
  7. O método importante para cuidar da segurança de login e logout é configure(HttpSecurity http)
  8. O trecho de código a seguir é usado para evitar o acesso não autorizado à “/homePage”. Se você tentar acessar esta página diretamente, será redirecionado automaticamente para a página “/loginPage”.
.antMatchers("/homePage").access("hasRole('ROLE_USER')")

Se removermos a chamada do método access(“hasRole(‘ROLE_USER’)”), então podemos acessar esta página sem fazer login em nossa aplicação. 13. Configuramos as funcionalidades de login e logout usando os métodos formLogin() e logout().

  • Habilitar Configuração do Spring MVC
    LoginApplicationConfig.java
package com.journaldev.spring.secuity.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc
@Configuration
@ComponentScan({ "com.journaldev.spring.*" })
@Import(value = { LoginSecurityConfig.class })
public class LoginApplicationConfig {
	@Bean
	public InternalResourceViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/views/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}
	
}

Explicação do Código:- Usamos a classe “LoginApplicationConfig” para definir os resolvedores de visualização do Spring MVC para evitar escrever o arquivo “web.xml”.

  1. @EnableWebMvc A anotação é usada para habilitar as funcionalidades de aplicação Spring Web MVC no Spring Framework
  2. @Import A anotação é usada para importar a classe de configuração do Spring Security para esta classe.
  3. @ComponentScan A anotação é usada para fazer a varredura de componentes no pacote especificado. É igual a “context:component-scan” na Configuração XML do Spring.
  • Inicializar Spring Security
package com.journaldev.spring.secuity.config.core;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

“SpringSecurityInitializer” é usado para registrar o DelegatingFilterProxy para usar o springSecurityFilterChain. Isso evita escrever a configuração de Filtros no arquivo web.xml.- Inicializar Aplicação Spring MVC
A classe “SpringMVCWebAppInitializer” é usada para inicializar o “DispatcherServlet” sem o arquivo web.xml em uma configuração baseada em anotações. SpringMVCWebAppInitializer.java

package com.journaldev.spring.secuity.config.core;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.journaldev.spring.secuity.config.LoginApplicationConfig;

public class SpringMVCWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { LoginApplicationConfig.class };
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return null;
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}
	
}

NOTA:-

  1. Quando acessamos nossa aplicação, por padrão, o método getServletMappings() do SpringMVCWebAppInitializer permitirá o acesso à URL raiz: “/”. Podemos substituir para redirecionar para uma URL diferente.
  2. A equipe do Spring ou Pivotal está trabalhando nesse problema para evitar a necessidade de tanto código Java, introduzindo uma anotação. Por favor, verifique em https://jira.spring.io/browse/SPR-10359.
  • Desenvolva o arquivo welcomePage.jsp
<h3>Welcome to JournalDEV Tutorials</h3>
<a href="${pageContext.request.contextPath}/loginPage">Login to Journal</a>
  • Desenvolva o arquivo loginPage.jsp
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<html>
<body onload='document.loginForm.username.focus();'>
	<h3>JournalDEV Tutorials</h3>

	<c:if test="${not empty error}"><div>${error}</div></c:if>
	<c:if test="${not empty message}"><div>${message}</div></c:if>

	<form name='login' action="<c:url value='/loginPage' />" method='POST'>
		<table>
			<tr>
				<td>UserName:</td>
				<td><input type='text' name='username' value=''></td>
			</tr>
			<tr>
				<td>Password:</td>
				<td><input type='password' name='password' /></td>
			</tr>
			<tr>
				<td colspan='2'><input name="submit" type="submit" value="submit" /></td>
			</tr>
		</table>
		<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
	</form>
</body>
</html>
  • Desenvolva o arquivo homepage.jsp
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<ul>
	<li>Java 8 tutorial</li>
	<li>Spring tutorial</li>
	<li>Gradle tutorial</li>
	<li>BigData tutorial</li>
</ul>

<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
	<a href="javascript:document.getElementById('logout').submit()">Logout</a>
</c:if>
  • A estrutura final do projeto se parece com isso:

Execute o Exemplo de Login e Logout do Spring Security MVC

Para executar esta aplicação web Spring, precisamos de um Contêiner Web que suporte o Spring 4 e ambientes Java 8 com Servlet 3.1.0.

  • Implante e execute no Spring TC Server no Spring STS Suite
  • Ele acessa automaticamente a URL da página de boas-vindas do nosso aplicativo conforme mostrado abaixo.
    – Clique no link “Login to JournalDEV” para acessar a página de login.
    – Agora, forneça informações de login incorretas e clique no botão “Login”.
    Aqui podemos observar a mensagem de erro: “Credenciais inválidas fornecidas.” – Agora, forneça as informações de login corretas configuradas na classe “LoginSecurityConfig”.
    Após o login bem-sucedido em nosso aplicativo, podemos ver a Página Inicial do nosso aplicativo com o link “Logout”. – Clique no link “Logout” para sair do aplicativo.
    Aqui podemos observar que saímos com sucesso do nosso aplicativo e fomos redirecionados para a página de login novamente. Podemos observar alguma mensagem de logout bem-sucedido nesta página de login.

NOTA:- Se observarmos este exemplo, não estamos usando o arquivo web.xml, certo. Como é uma Aplicação Web, o Maven procura pelo arquivo web.xml e gera alguns erros se não o encontrar na aplicação. Para evitar problemas relacionados ao Maven, precisamos configurar a flag “<failOnMissingWebXml>” no arquivo pom.xml. É isso, tudo sobre o Exemplo Simples do Módulo de Segurança do Spring 4. Desenvolveremos alguns exemplos mais úteis em tempo real em próximas postagens, como Gerenciamento de Funções, Recurso de Lembrar-Me, Segurança do WebSocket e mais. Por favor, deixe-me um comentário se gostou da minha postagem ou se tiver algum problema/sugestão.

Source:
https://www.digitalocean.com/community/tutorials/spring-4-security-mvc-login-logout-example