Hoy aprenderemos sobre Ejemplo de Inicio de Sesión con Spring Security. Antes de leer esta publicación, por favor revisa mi publicación anterior en “Introducción a Spring 4 Security” para obtener algunos conceptos básicos.
Ejemplo de Inicio y Cierre de Sesión con Spring Security
En esta publicación, vamos a desarrollar una aplicación web con Seguridad de Spring 4 MVC para proporcionar funciones de inicio y cierre de sesión utilizando la opción en memoria. Este ejemplo utiliza la configuración de Java de Spring con anotaciones de Spring, lo que significa que no se utiliza web.xml ni la Configuración XML de Spring (Estilo Antiguo). Si no estás familiarizado con el Módulo de Seguridad de Spring 3.x, por favor revisa las siguientes publicaciones primero para probar la Receta de Seguridad de Spring.
- Ejemplo de Seguridad de Spring MVC utilizando autenticación en memoria, UserDetailsService y autenticación JDBC
- Seguridad de Spring en una aplicación web Servlet utilizando autenticación DAO, JDBC, en memoria
El Módulo de Seguridad de Spring 4 admite las siguientes opciones para almacenar y gestionar las credenciales de usuario:
- Almacenamiento en Memoria
- Bases de Datos Relacionales (RDBMS)
- Almacenes de Datos No SQL
- LDAP
Vamos a usar la opción “In-Memory Store” en este ejemplo. Discutiremos otras opciones en mis próximas publicaciones. Vamos a utilizar Spring 4.0.2.RELEASE, Spring STS 3.7 Suite IDE, Spring TC Server 3.1 con Java 1.8 y la herramienta de construcción Maven para desarrollar este ejemplo.
Ejemplo de Inicio de Sesión de Spring Security
Vamos a desarrollar una lógica de inicio y cierre de sesión utilizando las características de seguridad de Spring 4. El objetivo principal de esta aplicación es desarrollar una aplicación sin usar “web.xml” y sin escribir una sola línea de configuración de beans XML de Spring. Eso significa que vamos a utilizar la función de configuración de Java de Spring con anotaciones de Spring. Desarrollaremos esta aplicación con las siguientes características:
- Página de Bienvenida
- Página de Inicio de Sesión
- Página de Inicio
- Funcionalidad de Cierre de Sesión
Por favor, utiliza los siguientes pasos para desarrollar y explorar este Ejemplo de Inicio de Sesión Simple de Spring 4 Security.
- Crea un Proyecto “Simple Spring Web Maven” en Spring STS Suite con los siguientes detalles
Project Name : SpringMVCSecruityMavenApp
- Actualiza el pom.xml con el siguiente contenido
<?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:- Si no estás familiarizado con la bandera “<failOnMissingWebXml>”, por favor, lee al final de esta publicación para obtener una buena comprensión del uso de este elemento.- Primero, desarrolla el Controlador de Inicio de Sesión utilizando la anotación @Controller de 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;
}
}
Explicación del código:- Hemos definido tres métodos en “LoginController” para manejar tres tipos diferentes de Solicitudes de Cliente
- welcomePage() manejará todas las solicitudes de cliente que estén utilizando la URI “/”.
- homePage() manejará todas las solicitudes de cliente que estén utilizando la URI “/homePage”.
- loginPage() manejará todas las solicitudes de cliente que estén utilizando la URI “/loginPage”.
- En loginPage(), nos encargamos de manejar mensajes de error y cierre de sesión.
- Luego, desarrollar una clase “LoginSecurityConfig” para proporcionar características de seguridad de inicio de sesión y cierre de sesión utilizando la API de Seguridad 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");
}
}
Explicación del código:- Hemos definido dos métodos en “LoginSecurityConfig” para almacenar y gestionar Credenciales de Usuario y encargarnos de las características de seguridad de inicio de sesión y cierre de sesión.
- @EnableWebSecurity La anotación se utiliza para habilitar la seguridad web en cualquier aplicación web.
- La anotación @EnableWebMVCSecurity se utiliza para habilitar la seguridad web en una aplicación web basada en Spring MVC.
NOTA:- @EnableWebSecurity = @EnableWebMVCSecurity + Características adicionales. Por eso, la anotación @EnableWebMVCSecurity está obsoleta en el marco de Spring 4.x. - La clase “LoginSecurityConfig” o cualquier clase designada para configurar Spring Security debe extender la clase “WebSecurityConfigurerAdapter” o implementar la interfaz relacionada.
- El método configureGlobal() se utiliza para almacenar y gestionar las credenciales de usuario.
- En el método configureGlobal(), podemos utilizar el método authorities() para definir los roles de nuestra aplicación como “ROLE_USER”. También podemos utilizar el método roles() para el mismo propósito.
- Diferencia entre los métodos authorities() y roles(): NOTA:- Desarrollaremos otro ejemplo para demostrar roles como “USER”, “ADMIN” en mis próximas publicaciones.
- El método importante para cuidar de la seguridad de inicio de sesión y cierre de sesión es configure(HttpSecurity http).
- El siguiente fragmento de código se utiliza para evitar el acceso no autorizado a “/homePage”. Si intenta acceder a esta página directamente, será redirigido automáticamente a la página “/loginPage”.
.antMatchers("/homePage").access("hasRole('ROLE_USER')")
Si eliminamos la llamada al método access(“hasRole(‘ROLE_USER’)”), entonces podemos acceder a esta página sin iniciar sesión en nuestra aplicación. Hemos configurado las funciones de inicio de sesión y cierre de sesión utilizando los métodos formLogin()
y logout()
.
- Habilitar la Configuración de 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;
}
}
Explicación del código:- Usamos la clase “LoginApplicationConfig” para definir los resolutores de vistas de Spring MVC y evitar escribir el archivo “web.xml”.
- @EnableWebMvc Se utiliza la anotación para habilitar las características de la aplicación de Spring Web MVC en el marco de Spring
- @Import La anotación se utiliza para importar la clase de configuración de Spring Security en esta clase.
- @ComponentScan La anotación se utiliza para escanear componentes en el paquete especificado. Es igual a “context:component-scan” en la Configuración XML de Spring.
- Inicializar Spring Security
package com.journaldev.spring.secuity.config.core;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
“SpringSecurityInitializer” se utiliza para registrar el DelegatingFilterProxy
para usar el springSecurityFilterChain. Evita escribir la configuración de filtros en el archivo web.xml.- Inicializar la aplicación Spring MVC
La clase “SpringMVCWebAppInitializer” se utiliza para inicializar “DispatcherServlet” sin archivo web.xml en una configuración basada en anotaciones. 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:-
- Cuando accedemos a nuestra aplicación, por defecto, `getServletMappings()` de `SpringMVCWebAppInitializer` permitirá acceder a la URL raíz: “/”. Podemos anular esto para redirigir a una URL diferente.
- El equipo de Spring o Pivotal está trabajando en este problema para evitar tanto código Java, mediante la introducción de una anotación. Por favor, verifica esto en https://jira.spring.io/browse/SPR-10359.
- Desarrolla el archivo welcomePage.jsp
<h3>Welcome to JournalDEV Tutorials</h3>
<a href="${pageContext.request.contextPath}/loginPage">Login to Journal</a>
- Desarrolla el archivo 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>
- Desarrolla el archivo 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>
Ejecutar Ejemplo de Inicio y Cierre de Sesión con Spring Security MVC
Para ejecutar esta aplicación web de Spring, necesitamos un contenedor web que admita Spring 4 y entornos Java 8 con Servlet 3.1.0.
- Implementar y ejecutar en Spring TC Server en Spring STS Suite
- Automáticamente accede a nuestra página de bienvenida de la aplicación como se muestra a continuación.
– haga clic en el enlace “Iniciar sesión en JournalDEV” para acceder a la página de inicio de sesión.
– Ahora, proporcione detalles de inicio de sesión incorrectos y haga clic en el botón “Iniciar sesión”.
Aquí podemos observar este mensaje de error: “Credenciales inválidas proporcionadas.”- Ahora, proporcione detalles de inicio de sesión correctos configurados en la clase “LoginSecurityConfig”.
Después de iniciar sesión correctamente en nuestra aplicación, podemos ver nuestra página de inicio de la aplicación con el enlace “Cerrar sesión”.- haga clic en el enlace “Cerrar sesión” para cerrar la sesión de la aplicación.
Aquí podemos observar que hemos cerrado la sesión de nuestra aplicación con éxito y hemos sido redirigidos a la página de inicio de sesión nuevamente. Podemos observar algunos mensajes de cierre de sesión exitoso en esta página de inicio de sesión.
NOTA:- Si observamos este ejemplo, no estamos utilizando correctamente el archivo web.xml. Como se trata de una aplicación web, Maven busca el archivo web.xml y genera algunos errores si no lo encuentra en la aplicación. Para evitar problemas relacionados con Maven, necesitamos configurar el indicador “
Source:
https://www.digitalocean.com/community/tutorials/spring-4-security-mvc-login-logout-example