Hoy vamos a analizar el ejemplo de acceso y autorización basado en roles de Spring Security. Sin embargo, antes de leer esta publicación, por favor revisa mi publicación anterior sobre “Ejemplo de inicio y cierre de sesión de Spring 4 Security MVC” para obtener algunos conocimientos básicos sobre Spring 4 Security.
Rol de Spring Security
En esta publicación, discutiremos cómo definir, usar y gestionar roles de seguridad de Spring como “USER”, “ADMIN” en una aplicación web de Spring. Al igual que en mi publicación anterior, este ejemplo también utiliza Spring 4 MVC Security con In-Memory Store y la característica de configuración Java de Spring para desarrollar la aplicación. Esto significa que no vamos a usar el archivo web.xml y tampoco escribiremos ni una sola línea de configuración XML de Spring. Utilizaremos la opción “In-Memory Store” para almacenar y gestionar las credenciales de usuario. 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 Autorización de Acceso Basado en Roles de Spring Security
- Cree un proyecto “Simple Spring Web Maven” en Spring STS Suite con los siguientes detalles.
Nombre del Proyecto: SpringMVCSecruityMavenRolesApp2. Utilice el mismo archivo pom.xml de mi publicación anterior con los siguientes cambios
<artifactId>SpringMVCSecruityMavenRolesApp</artifactId>
<build>
<finalName>SpringMVCSecruityMavenRolesApp</finalName>
</build>
</project>
- Utilice todos los archivos Java y JSP de mi publicación anterior. Discutiremos solo el contenido actualizado o recién agregado aquí.
- Actualice el archivo LoginSecurityConfig.java para configurar roles de usuario como “USER” y “ADMIN”.
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("jduser").password("jdu@123").authorities("ROLE_USER")
.and()
.withUser("jdadmin").password("jda@123").authorities("ROLE_USER","ROLE_ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/homePage").access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
.antMatchers("/userPage").access("hasRole('ROLE_USER')")
.antMatchers("/adminPage").access("hasRole('ROLE_ADMIN')")
.and()
.formLogin().loginPage("/loginPage")
.defaultSuccessUrl("/homePage")
.failureUrl("/loginPage?error")
.usernameParameter("username").passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/loginPage?logout");
}
}
Explicación del Código
- En el método configureGlobal(), hemos agregado dos usuarios: Un usuario con el rol “ROLE_USER” y otro usuario con los roles “ROLE_USER” y “ROLE_ADMIN”. Esto significa que este segundo usuario actuará como usuario administrador. De esta manera, podemos configurar cualquier número de usuarios y roles.
- Podemos usar tanto el método authorities(ROLE) como el método roles(ROLE) para configurar roles en nuestra aplicación.
- Diferencia entre los métodos authorities() y roles():
- authorities() necesita el nombre completo del rol como “ROLE_USER”
- roles() necesita el nombre del rol como “USER”. Agregará automáticamente el valor “ROLE_” a este nombre de rol “USER”.
- En el método configure(), hemos definido diferentes URL con roles de acceso requeridos.
antMatchers("/homePage")
.access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
Este fragmento de código configura que “/homePage” está disponible para ambos roles de USER y ADMIN.
.antMatchers("/userPage").access("hasRole('ROLE_USER')")
.antMatchers("/adminPage").access("hasRole('ROLE_ADMIN')")
Este fragmento de código configura que “/userPage” es accesible solo por el rol “USER” y “/adminPage” es accesible solo por el rol “ADMIN”. Si otros roles intentan acceder a estas páginas, recibiremos el mensaje de error “403 Access is Denied”.
- Actualice el archivo Controlador LoginController.java para definir nuevos caminos de acceso URL como se muestra a continuación.
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 = {"/userPage"}, method = RequestMethod.GET)
public ModelAndView userPage() {
ModelAndView model = new ModelAndView();
model.setViewName("userPage");
return model;
}
@RequestMapping(value = {"/adminPage"}, method = RequestMethod.GET)
public ModelAndView adminPage() {
ModelAndView model = new ModelAndView();
model.setViewName("adminPage");
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 Además del ejemplo anterior, aquí hemos agregado dos URLs nuevas más.
-
“/userPage” es utilizado por el Rol USUARIO para acceder y realizar actividades de usuario normales.
-
“/adminPage” es utilizado por el Rol ADMIN para acceder y realizar actividades de usuario administrador. El rol ADMIN también puede acceder a la URL “/userPage”.
-
Se actualizó el archivo homePage.jsp para proporcionar actividades específicas para los Roles de Usuario y Administrador.
homePage.jsp
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<a href="${pageContext.request.contextPath}/userPage">JD User</a> | <a href="${pageContext.request.contextPath}/adminPage">JD Admin</a> | <a href="javascript:document.getElementById('logout').submit()">Logout</a>
<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>
Aquí hemos agregado tres opciones de menú en la parte superior. “Cerrar sesión” ya se discutió en mi publicación anterior. Los dos nuevos enlaces son:
- JD Usuario: Accesible por los Roles “USUARIO” y “ADMIN”
- JD Administrador: Accesible solo por los Roles “ADMIN”
NOTA:- En aplicaciones en tiempo real, mostraremos solo el enlace “JD Usuario” al Rol “USUARIO” y ocultaremos el enlace “JD Administrador”. Para probar si es accesible por el Rol “USUARIO” o no y también para ver el mensaje de error exacto, no hemos ocultado este enlace.Se agregó un nuevo archivo adminPage.jsp para actuar como una página de inicio para el Rol “ADMIN”.
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<h3>Admin Page</h3>
<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>
- userPage.jsp
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<h3>User Page</h3>
<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>
¡Agrega un nuevo archivo userPage.jsp para que actúe como página de inicio para el rol “USER”!
Prueba de la aplicación de ejemplo con roles de seguridad de Spring
- Haz clic derecho en el proyecto en el entorno de desarrollo integrado Spring STS y selecciona la opción “Ejecutar como >> Ejecutar en servidor”. Accederá a la página de bienvenida de la aplicación por defecto como se muestra a continuación:
3. Haz clic en el enlace “Iniciar sesión en JournalDEV”. Ahora estás en la página de inicio de sesión.
5. Primero inicia sesión con las credenciales de rol “USER”: Nombre de usuario: jduser Contraseña: jdu@123
Ahora veremos la página de inicio de la aplicación con 3 opciones de menú: “Usuario JD”, “Administrador JD” y “Cerrar sesión”. Haz clic en el enlace “Usuario JD”. Como hemos iniciado sesión en la aplicación usando las credenciales de rol “USER”, podemos acceder a este enlace como se muestra a continuación.
Simplemente usa la flecha hacia atrás en Spring STS IDE y esta vez haz clic en el enlace “Administrador JD”.
Como hemos iniciado sesión con las credenciales de rol “USER”, no podemos acceder a este enlace. Por eso vimos este mensaje de error: “403 Acceso denegado”.9. Ahora cierra sesión y vuelve a iniciar sesión con las credenciales de rol “ADMIN” Nombre de usuario: jdadmin Contraseña: jda@123 Esta vez podemos acceder al enlace “Administrador JD” correctamente como se muestra a continuación.
Prueba el enlace “Cerrar sesión” para salir de la aplicación.
Eso es todo sobre el ejemplo de roles de seguridad de Spring para proporcionar acceso autorizado a las páginas de la aplicación web.