Exemple de connexion/déconnexion de sécurité MVC Spring 4

Aujourd’hui, nous allons apprendre sur l’exemple de connexion à Spring Security. Avant de lire cet article, veuillez consulter mon précédent post sur l’introduction à Spring 4 Security pour acquérir quelques notions de base.

Exemple de connexion et déconnexion à Spring Security

Dans cet article, nous allons développer une application Web Spring 4 MVC Security pour fournir des fonctionnalités de connexion et de déconnexion en utilisant l’option In-Memory. Cet exemple utilise la configuration Java Spring avec des annotations, ce qui signifie qu’il ne nécessite pas l’utilisation de web.xml et de la configuration XML Spring (ancien style). Si vous n’êtes pas familier avec le module de sécurité Spring 3.x, veuillez consulter les articles suivants pour découvrir la recette de Spring Security.

  1. Exemple de sécurité Spring MVC utilisant la mémoire, UserDetailsService et l’authentification JDBC
  2. Sécurité Spring dans une application Web Servlet utilisant DAO, JDBC, authentification en mémoire

Le module de sécurité Spring 4 prend en charge les options suivantes pour stocker et gérer les informations d’identification des utilisateurs :

  1. Stockage en mémoire
  2. Bases de données relationnelles (RDBMS)
  3. Magasins de données NoSQL
  4. LDAP

Nous utiliserons l’option « En mémoire » dans cet exemple. Nous discuterons d’autres options dans mes prochains articles. Nous allons utiliser Spring 4.0.2.RELEASE, Spring STS 3.7 Suite IDE, Spring TC Server 3.1 avec Java 1.8 et l’outil de construction Maven pour développer cet exemple.

Exemple de connexion à Spring Security

Nous allons développer une logique de connexion et de déconnexion en utilisant les fonctionnalités de sécurité de Spring 4. L’objectif principal de cette application est de développer une application sans utiliser de « web.xml » et sans écrire une seule ligne de configuration des beans XML de Spring. Cela signifie que nous allons utiliser la fonctionnalité Spring Java Config avec les annotations Spring. Nous allons développer cette application avec les fonctionnalités suivantes :

  1. Page de bienvenue
  2. Page de connexion
  3. Page d’accueil
  4. Fonction de déconnexion

Veuillez suivre les étapes suivantes pour développer et explorer cet exemple de connexion simple à Spring 4 Security.

  • Créez un projet « Simple Spring Web Maven » dans Spring STS Suite avec les détails suivants
   Project Name : SpringMVCSecruityMavenApp
  • Mettez à jour pom.xml avec le contenu suivant
<?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>

REMARQUE :- Si vous n’êtes pas familier avec le drapeau « <failOnMissingWebXml> », veuillez lire à la fin de cet article pour comprendre correctement l’utilisation de cet élément.- Tout d’abord, développez le contrôleur de connexion en utilisant l’annotation @Controller.
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;
	}

}

Explication du code :- Nous avons défini trois méthodes dans « LoginController » pour gérer trois types différents de demandes de clients

  1. laPageBienvenue() gérera toutes les demandes de clients qui utilisent l’URI « / ».
  2. laPageAccueil() gérera toutes les demandes de clients qui utilisent l’URI « /homePage ».
  3. laPageConnexion() gérera toutes les demandes de clients qui utilisent l’URI « /loginPage ».
  4. Dans laPageConnexion(), nous prenons soin de gérer les messages d’erreur et de déconnexion.
  • Ensuite, développez une classe « LoginSecurityConfig » pour fournir des fonctionnalités de sécurité de connexion et de déconnexion à l’aide de l’API de sécurité 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"); 
		
	}
}

Explication du code :- Nous avons défini deux méthodes dans « LoginSecurityConfig » pour stocker et gérer les informations d’identification utilisateur et prendre en charge les fonctionnalités de sécurité de connexion et de déconnexion.

  1. @EnableWebSecurity L’annotation est utilisée pour activer la sécurité web dans n’importe quelle application web.
  2. @EnableWebMVCSecurity« ` L’annotation est utilisée pour activer la sécurité web dans une application web basée sur Spring MVC.
    « `NOTE:-« ` « `@EnableWebSecurity« ` = « `@EnableWebMVCSecurity« ` + Fonctionnalités supplémentaires. C’est pourquoi l’annotation « `@EnableWebMVCSecurity« ` est obsolète dans le framework Spring 4.x. « `
  3. « `La classe « LoginSecurityConfig » ou toute classe destinée à configurer la sécurité Spring devrait étendre la classe « WebSecurityConfigurerAdapter » ou implémenter l’interface associée. « `
  4. « `La méthode « `configureGlobal()« ` est utilisée pour stocker et gérer les informations d’identification de l’utilisateur. « `
  5. « `Dans la méthode « `configureGlobal()« `, nous pouvons utiliser la méthode « `authorities()« ` pour définir les rôles de notre application tels que « ROLE_USER ». Nous pouvons également utiliser la méthode « `roles()« ` à la même fin. « `
  6. « `Différence entre les méthodes « `authorities()« ` et « `roles()« ` : « `NOTE:-« ` La méthode « `authorities()« ` nécessite un nom de rôle complet comme « ROLE_USER », tandis que la méthode « `roles()« ` nécessite un nom de rôle tel que « USER ». Il ajoutera automatiquement la valeur « ROLE_ » à ce nom de rôle « USER ». « `
  7. « `Nous développerons un autre exemple pour illustrer les rôles tels que « USER », « ADMIN » dans mes prochains articles. « `
  8. « `La méthode importante pour gérer la sécurité de connexion et déconnexion est « `configure(HttpSecurity http)« `. Le code suivant est utilisé pour éviter l’accès non autorisé à « /homePage ». Si vous essayez d’accéder directement à cette page, vous serez redirigé automatiquement vers « /loginPage ».
.antMatchers("/homePage").access("hasRole('ROLE_USER')")

Si nous supprimons l’appel à la méthode access(“hasRole(‘ROLE_USER’)”), nous pouvons accéder à cette page sans nous connecter à notre application.13. Nous avons configuré les fonctionnalités de connexion et de déconnexion à l’aide des méthodes formLogin() et logout().

  • Activer la configuration 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;
	}
	
}

Explication du code :- Nous utilisons la classe « LoginApplicationConfig » pour définir les résolveurs de vue Spring MVC afin d’éviter d’écrire le fichier « web.xml ».

  1. @EnableWebMvc Annotation est utilisée pour activer les fonctionnalités de l’application Spring Web MVC dans le framework Spring
  2. @Import Annotation est utilisée pour importer la classe de configuration de la sécurité Spring dans cette classe.
  3. @ComponentScan Annotation est utilisée pour effectuer une analyse des composants dans le package spécifié. C’est équivalent à « context:component-scan » dans la configuration Spring XML.
  • Initialiser la sécurité Spring
package com.journaldev.spring.secuity.config.core;

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

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

“SpringSecurityInitializer” est utilisé pour enregistrer le DelegatingFilterProxy afin d’utiliser le springSecurityFilterChain. Cela évite d’écrire la configuration des filtres dans le fichier web.xml. – Initialiser l’application Spring MVC
La classe « SpringMVCWebAppInitializer » est utilisée pour initialiser le « DispatcherServlet » sans fichier web.xml dans une configuration basée sur les annotations. 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[] { "/" };
	}
	
}

NOTE :-

  1. Lorsque nous accédons à notre application, par défaut, la méthode `getServletMappings()` de `SpringMVCWebAppInitializer` permet d’accéder à l’URL racine : « / ». Nous pouvons la remplacer pour rediriger vers une URL différente.
  2. L’équipe Spring ou Pivotal travaille sur ce problème afin de réduire le code Java en introduisant une annotation. Consultez ceci à l’adresse https://jira.spring.io/browse/SPR-10359.
  • Développez le fichier welcomePage.jsp
<h3>Welcome to JournalDEV Tutorials</h3>
<a href="${pageContext.request.contextPath}/loginPage">Login to Journal</a>
  • Développez le fichier 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>
  • Développez le fichier 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>
  • La structure finale du projet ressemble à ceci :

Exécutez l’exemple de connexion/déconnexion MVC de Spring Security

Pour exécuter cette application Web Spring, nous avons besoin d’un conteneur Web prenant en charge Spring 4 et Java 8 avec un conteneur Servlet 3.1.0.

  • Déployez et exécutez sur Spring TC Server dans Spring STS Suite.
  • Il accède automatiquement à notre URL de page de bienvenue de l’application comme indiqué ci-dessous.
    – cliquez sur le lien « Connexion à JournalDEV » pour accéder à la page de connexion.
    – Maintenant, fournissez des détails de connexion incorrects et cliquez sur le bouton « Connexion ».
    Ici, nous pouvons observer ce message d’erreur : « Identifiants invalides fournis. »- Fournissez maintenant les détails de connexion corrects configurés dans la classe « LoginSecurityConfig ».
    Après une connexion réussie à notre application, nous pouvons voir notre page d’accueil de l’application avec le lien « Déconnexion ».- cliquez sur le lien « Déconnexion » pour vous déconnecter de l’application.
    Ici, nous pouvons observer que nous sommes déconnectés de notre application avec succès et redirigés vers la page de connexion à nouveau. Nous pouvons observer un message de déconnexion réussie sur cette page de connexion.

NOTE:- Si nous observons cet exemple, nous n’utilisons pas correctement le fichier web.xml. Comme il s’agit d’une application Web, Maven recherche le fichier web.xml et génère des erreurs s’il ne le trouve pas dans l’application. Pour éviter les problèmes liés à Maven, nous devons configurer le drapeau « <failOnMissingWebXml> » dans le fichier pom.xml. C’est tout pour cet exemple simple du module de sécurité Spring 4. Nous développerons d’autres exemples utiles en temps réel dans mes prochains articles, tels que la gestion des rôles, la fonction Remember-Me, la sécurité WebSocket, et plus encore. N’hésitez pas à me laisser un commentaire si vous aimez mon article ou si vous avez des problèmes/suggestions.

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