Oggi impareremo l’esempio di accesso a Spring Security. Prima di leggere questo post, ti prego di dare un’occhiata al mio post precedente su “Introduzione a Spring 4 Security” per avere le basi.
Esempio di accesso e logout in Spring Security
In questo post, svilupperemo un’applicazione web Spring 4 MVC Security per fornire funzionalità di accesso e logout utilizzando l’opzione In-Memory. Questo esempio utilizza Spring Java Config con Spring Annotations, il che significa senza utilizzare web.xml e la configurazione XML di Spring (vecchio stile). Se non sei familiare con il modulo di sicurezza di Spring 3.x, ti prego di dare prima un’occhiata ai seguenti post per assaggiare la ricetta di Spring Security.
- Esempio di sicurezza Spring MVC utilizzando l’autenticazione in-memory, UserDetailsService e JDBC
- Sicurezza Spring in un’applicazione web Servlet utilizzando DAO, JDBC, autenticazione in-memory
Il modulo di sicurezza di Spring 4 supporta le seguenti opzioni per memorizzare e gestire le credenziali degli utenti:
- Memorizzazione in memoria
- Database relazionali (RDBMS)
- Archivi di dati NoSQL
- LDAP
Creeremo un’applicazione di accesso sicuro utilizzando l’opzione “In-Memory Store” in questo esempio. Discuteremo delle altre opzioni nei miei prossimi post. Utilizzeremo Spring 4.0.2.RELEASE, Spring STS 3.7 Suite IDE, Spring TC Server 3.1 con Java 1.8 e lo strumento di compilazione Maven per sviluppare questo esempio.
Esempio di accesso alla sicurezza di Spring
Stiamo sviluppando una logica di accesso e disconnessione utilizzando le funzionalità di sicurezza di Spring 4. L’obiettivo principale di questa applicazione è sviluppare un’applicazione senza utilizzare “web.xml” e senza scrivere una singola riga di configurazione dei bean XML di Spring. Ciò significa che useremo la funzionalità Spring Java Config con le annotazioni di Spring. Svilupperemo questa applicazione con le seguenti caratteristiche:
- Pagina di benvenuto
- Pagina di accesso
- Pagina principale
- Funzione di disconnessione
Seguire i seguenti passi per sviluppare ed esplorare questo esempio di accesso semplice di Spring 4 Security.
- Creare un progetto “Simple Spring Web Maven” in Spring STS Suite con i seguenti dettagli
Project Name : SpringMVCSecruityMavenApp
- Aggiornare il file pom.xml con il seguente contenuto
<?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 non si è a conoscenza del flag “<failOnMissingWebXml>”, si prega di leggere alla fine di questo post per comprendere bene l’utilizzo di questo elemento.- Prima di tutto, sviluppare il controller di accesso utilizzando l’annotazione @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;
}
}
Spiegazione del codice:- Abbiamo definito tre metodi in “LoginController” per gestire tre tipi diversi di richieste da parte del cliente
- welcomePage() gestirà tutte le richieste del cliente che utilizzano l’URI “/”
- homePage() gestirà tutte le richieste del cliente che utilizzano l’URI “/homePage”
- loginPage() gestirà tutte le richieste del cliente che utilizzano l’URI “/loginPage”
- In loginPage(), ci occupiamo della gestione degli errori e dei messaggi di logout.
- Quindi sviluppare una classe “LoginSecurityConfig” per fornire funzionalità di sicurezza di accesso e logout utilizzando l’API di sicurezza 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");
}
}
Spiegazione del codice:- Abbiamo definito due metodi in “LoginSecurityConfig” per memorizzare e gestire le credenziali dell’utente e occuparci delle funzionalità di sicurezza di accesso e logout.
- @EnableWebSecurity L’annotazione viene utilizzata per abilitare la sicurezza web in qualsiasi applicazione web.
- @EnableWebMVCSecurity L’annotazione viene utilizzata per abilitare la sicurezza web nell’applicazione web basata su Spring MVC.
NOTA:- @EnableWebSecurity = @EnableWebMVCSecurity + Funzionalità aggiuntive. Ecco perché l’annotazione @EnableWebMVCSecurity è deprecata nel framework Spring 4.x. La classe “LoginSecurityConfig” o qualsiasi classe designata per configurare la sicurezza di Spring, dovrebbe estendere la classe “WebSecurityConfigurerAdapter” o implementare l’interfaccia correlata.
- Il metodo configureGlobal() viene utilizzato per memorizzare e gestire le credenziali utente.
- Nel metodo configureGlobal(), possiamo utilizzare il metodo authorities() per definire i ruoli della nostra applicazione come “ROLE_USER”. Possiamo anche utilizzare il metodo roles() per lo stesso scopo.
- Differenza tra i metodi authorities() e roles():
- authorities() richiede un nome ruolo completo come “ROLE_USER” roles() richiede un nome ruolo come “USER”. Aggiungerà automaticamente il valore “ROLE_” a questo nome ruolo “USER”. NOTA:- Svilupperemo un altro esempio per dimostrare Ruoli come “USER”, “ADMIN” nei miei prossimi post.
- Il metodo importante per gestire la sicurezza del login e del logout è configure(HttpSecurity http)
- Il seguente codice snippet viene utilizzato per evitare l’accesso non autorizzato a “/homePage”. Se si tenta di accedere direttamente a questa pagina, verrà reindirizzato automaticamente alla pagina “/loginPage”.
.antMatchers("/homePage").access("hasRole('ROLE_USER')")
Se rimuoviamo la chiamata al metodo access(“hasRole(‘ROLE_USER’)”), allora possiamo accedere a questa pagina senza effettuare il login nella nostra applicazione. 13. Abbiamo configurato le funzionalità di login e logout utilizzando i metodi formLogin() e logout().
- Abilita la Configurazione di 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;
}
}
Spiegazione del Codice:- Utilizziamo la classe “LoginApplicationConfig” per definire i Visualizzatori di Risorse di Spring MVC al fine di evitare la scrittura del file “web.xml”.
- @EnableWebMvc è utilizzato per abilitare le funzionalità dell’applicazione Spring Web MVC nel framework Spring
- @Import è utilizzato per importare la classe di configurazione di Spring Security in questa classe.
- @ComponentScan è utilizzato per eseguire la scansione dei componenti nel pacchetto specificato. Equivale a “context:component-scan” nella configurazione XML di Spring.
- Inizializza la Sicurezza di Spring
package com.journaldev.spring.secuity.config.core;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
“SpringSecurityInitializer” è utilizzato per registrare il DelegatingFilterProxy
per utilizzare la springSecurityFilterChain. Evita la scrittura della configurazione dei filtri nel file web.xml. – Inizializza l’Applicazione Spring MVC
La classe “SpringMVCWebAppInitializer” è utilizzata per inizializzare il “DispatcherServlet” senza il file web.xml in una configurazione basata su annotazioni. 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:-
- Quando accediamo alla nostra applicazione, di default il metodo getServletMappings() di SpringMVCWebAppInitializer permetterà di accedere all’URL radice: “/”. Possiamo sovrascrivere per reindirizzare a un URL diverso.
- Il team di Spring o Pivotal sta lavorando su questa problematica per evitare di scrivere così tanto codice Java, introducendo un’annotazione. Si prega di controllare questo su https://jira.spring.io/browse/SPR-10359.
- Sviluppare il file welcomePage.jsp
<h3>Welcome to JournalDEV Tutorials</h3>
<a href="${pageContext.request.contextPath}/loginPage">Login to Journal</a>
- Sviluppare il file 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>
- Sviluppare il file 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>
Eseguire l’esempio di Login Logout di Spring Security MVC
Per eseguire questa Applicazione Web Spring, abbiamo bisogno di un Contenitore Web che supporti Spring 4 e Java 8 con Servlet 3.1.0 Container.
- Deploy e Esegui su Spring TC Server nella Suite Spring STS
- Automaticamente accede all’URL della pagina di benvenuto della nostra applicazione come mostrato di seguito.
– fare clic sul link “Accedi a JournalDEV” per accedere alla pagina di accesso.
– Ora, fornire dati di accesso errati e fare clic sul pulsante “Accedi”.
Qui possiamo osservare questo messaggio di errore: “Credenziali non valide fornite.”- Ora, fornire i dettagli di accesso corretti configurati nella classe “LoginSecurityConfig”.
Dopo aver effettuato l’accesso con successo alla nostra applicazione, possiamo vedere la nostra Homepage dell’applicazione con il link “Logout”.- fare clic sul link “Logout” per disconnettersi dall’applicazione.
Qui possiamo osservare di essere stati disconnessi con successo dalla nostra applicazione e reindirizzati nuovamente alla pagina di accesso. Possiamo osservare alcuni messaggi di logout riuscito in questa pagina di accesso.
NOTA:- Se osserviamo questo esempio, non stiamo utilizzando correttamente il file web.xml. Poiché si tratta di un’applicazione web, Maven cerca il file web.xml e genera alcuni errori se non lo trova nell’applicazione. Per evitare problemi legati a Maven, è necessario configurare il flag “<failOnMissingWebXml>” nel file pom.xml. Ecco tutto riguardo all’esempio semplice del modulo di sicurezza Spring 4. Svilupperemo ulteriori esempi utili in tempo reale nei miei prossimi articoli, come la gestione dei ruoli, la funzione Remember-Me, la sicurezza WebSocket e altro ancora. Lasciami un commento se ti è piaciuto il mio articolo o se hai problemi/suggerimenti.
Source:
https://www.digitalocean.com/community/tutorials/spring-4-security-mvc-login-logout-example