0% encontró este documento útil (0 votos)
669 vistas

Spring Security

El documento describe las características principales de Spring Security 3.0, incluyendo: 1) Spring Security se ha convertido en la librería de referencia para autenticación y autorización en Java debido a su código excelente, uso extendido, solución madura, facilidad de configuración e integración, y documentación. 2) El proceso de autenticación en Spring Security involucra objetos Authentication, SecurityContextHolder, y UserDetailsService que interactúan con el AuthenticationManager. 3) La configuración de Spring Security se simplifica mucho usando el namespace de configur
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
669 vistas

Spring Security

El documento describe las características principales de Spring Security 3.0, incluyendo: 1) Spring Security se ha convertido en la librería de referencia para autenticación y autorización en Java debido a su código excelente, uso extendido, solución madura, facilidad de configuración e integración, y documentación. 2) El proceso de autenticación en Spring Security involucra objetos Authentication, SecurityContextHolder, y UserDetailsService que interactúan con el AuthenticationManager. 3) La configuración de Spring Security se simplifica mucho usando el namespace de configur
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 10

El contenido de este post, es consecuencia de la presentación realizada en el SpringGxDay

celebrado en Boadilla del Monte el día 19 de Febrero de 2010, y en el que Paradigma Tecnológico
fue partner del evento. A continuación, se expone brevemente, las características principales que
presenta Spring Security 3.0.

Spring Security se ha convertido en la librería de referencia dentro del mundo Java, para dar
soporte a los servicios de autenticación y autorización de una aplicación. Las razones del por qué
esta librería se ha convertido en referencia son:

- Proyecto enmarcado dentro de las soluciones de Spring Framework, y todo lo que ello conllleva:

 Código y diseño del componente excelente


 Gran uso en proyectos de referencia dentro del sector Java
 Solución madura (con versiones estables desde el año 2003).
 Facilidad de configuración y parametrización (gracias al uso de namespace para la
configuración y al uso del patrón dependency Injection).
 Integración con los sistemas legacy de autenticación más importantes del mercado:
BBDD, LDAP, CAS (para single sign-on), gestión de certificados, etc.
 Como todo componente realizado dentro de la familia Spring es de fácil uso y fácil
extensibilidad.
 Gran cantidad de documentación y ejemplo de soporte.

Una vez definidas las características principales que han convertido a Spring Security en la librería
referente, para dar solución a la seguridad de aplicaciones, pasaremos a comentar las principales
funcionalidades que presenta la librería y una breve descripción de cada una de ellas.

Autenticación en Spring Security

Antes de nada, definir que un proceso de autenticación consiste en identificar a la “entidad” que
realiza una acción sobre la aplicación y garantizar que es quién dice ser. La entidad que realiza una
acción sobre la aplicación es conocida con el nombre de principal.

Desde el punto de vista de la arquitectura del módulo de seguridad, el componente principal es


AuthenticationManager el cual es el componente encargado de implementar el proceso de
autenticación en las aplicaciones.

Antes de describir como es el diseño de AuthenticationManager, es necesario introducir algunos


componentes que juegan un especial rol, y que son necesarios para poder comprender el proceso
de autenticación dentro de Spring Security.

 Objeto Authentication. Dentro de este componente se guardan los datos asociados al


principal, así como el conjunto de autoridades (roles) que posee dicho principal. Este
objeto Authentication es en el que se apoya el AuthenticationManager para implementar el
servicio de autenticación.
 Objeto SecurityContextHolder. Este componente es el encargado de guardar los datos
del principal y sus roles (autoridades) dentro del contexto de seguridad. Como hemos
comentado, la información del principal y los roles asociados están encapsulados dentro
del objeto Authentication, por tanto el SecurityContextHolder guarda el objeto
Authentication en el contexto de seguridad. Normalmente, en casi todas las aplicaciones el
contexto de seguridad coincide con el ThreadLocal, lo cual permite que la información que
reside en el objeto Authentication pueda ser consultada en todo momento por cualquier
componente dentro de nuestra aplicación.
 Objeto UserDetailsService. Como casi siempre en Spring, se produce un modelo de
delegación de responsabilidades, con lo que el objeto AuthenticationManager delega en el
objeto UserDetails las labores de obtención de la información del usuario sobre el
repositorio de seguridad. Por ejemplo, si el repositorio de usuarios, credenciales y roles
de la aplicación están en BBDD, el objeto UserDetails será el encargado de realizar las
oportunas consultas que obtengan toda la información del principal a partir del esquema
de BBDD correspondiente.

Volviendo al componente AuthenticationManager, este interfaz únicamente implementa el método:

Authentication authenticate (Authentication authentication) throws AuthtenticationException;

Como puede ver el lector, el parámetro de entrada authentication básicamente tendrá los datos
básicos del principal (en un ejemplo sencillo el nombre de usuario peticionario). Con este dato, se
procederá a obtener toda la información de credenciales asociadas con el principal, y se
comprobará si dichas credenciales son correctas. En el caso que el sistema de seguridad sea basado
en username y password, se comprobará que la password pasada por el usuario, es correcta
(buscando para ello la credencial dentro del repositorio de seguridad configurado en la aplicación).
En el caso que el proceso de autenticación no sea correcto (credenciales incorrectas o nombre de
usuario no válido) el componente lanzará la correspondiente AuthenticationException. En el caso
que el proceso de autenticación, por el contrario, sea correcto, se procederá a obtener los roles
(autoridades) asociadas al principal y serán guardadas en el objeto Authentication, que será
devuelto por el AuthenticationManager. Finalmente este objeto Authentication será guardado por
el componente SecurityContextHolder en el contexto de seguridad oportuno (normalmente el
ThreadLocal).

Como anteriormente se comentó, un modelo que se repite mucho en las soluciones de Spring es la
delegación de responsabilidades dentro de los distintos componentes de la arquitectura. En
el caso del AuthenticationManager, se dispone de un conjunto de componentes ProviderManager
los cuales son los encargados de implementar el proceso de autenticación. Los objetos
ProviderManager están más cercanos a la tecnología usada para implementar el repositorio de
seguridad de la aplicación. Así por ejemplo, si nuestra sistema de autenticación está soportado
mediante un directorio activo, dispondremos de un objeto LdapAuthenticationProvider encargado
de realizar las labores de autenticación contra dicho directorio activo.

A continuación se presenta un diagrama donde se ve la estructura de las clases envueltas en el


proceso de autenticación:

Diagrama de clases Autenticación en Spring Security

Diagrama de colaboración AuthenticationManager

En el último diagrama se puede observar como los distintos componentes colaboran entre sí para
implementar el proceso de autenticación de una aplicación.
Por suerte, Spring Security viene con la implementación de numerosos ProviderManager que
dan cabida a la integración con distintos sistemas de soporte para el proceso de autenticación.
Simplemente es necesario configurar dichos componentes para adaptarlos a la particularidad que
pueda tener la aplicación que estemos desarrollando.

Configuración de Spring Security con namespace

Una de las principales ventajas introducidas en la versión 2.5 de Spring Security es la inclusión de
un namespace específico, que da soporte a la configuración de los distintos componentes que
forman parte de la solución de autenticación y autorización de aplicaciones. Anteriormente a esta
versión, era necesario definir un conjunto de beans muy extenso y existía la posibilidad de
error en la gestión de las dependencias de los distintos beans. Gracias a la incorporación de
namespace a la solución, al desarrollar se le abstrae de muchas particularidades internas de la
solución, proporcionando un fichero XML de configuración (namespace) que hace la labor de
parametrización mucho más sencilla. Así por ejemplo si queremos configurar un componente
AuthenticationManager que acceda a BBDD para la obtención de las credenciales y roles aplicación
bastaría con incluir la siguiente porción de código XML dentro del fichero de configuración de la
librería:

Configuración de AuthenticationManager mediante namespace

Como se puede ver en el ejemplo, el único parámetro necesario para configurar el gestor de
autenticación es el datasource que indicará donde está el esquema de Base de datos donde reside el
repositorio con los datos de seguridad.

Como iremos viendo en este post, el fichero de configuración permitiría la configuración de todos
los elementos necesarios para realizar la autenticación y autorización de una aplicación web sobre
protocolo http.

Seguridad de aplicaciones web

Aunque Spring Security permite introducir servicios de autenticación y autorización


independientemente de que la aplicación sea web, a continuación se detallará cómo se configura
Spring Security para permitir introducir procesos de autenticación y autorización en aplicaciones
web que corren bajo el protocolo HTTP.

Bien, lo primero que es necesario definir para proceder a autenticar y autorizar una aplicación web
con Spring Security es la definición de un ServletFilter, concretamente DelegatingFilterProxy.
Básicamente lo que realiza este filtro es, como su propio nombre indica, de proxy entre un entorno
gestionado por el contexto de servlets y un entorno gestionado por el contexto de aplicación de
Spring. Lo que permite este filtro, por tanto es que todos los componentes que forman parte de
la arquitectura de Spring Security puedan ser definidos mediante los ficheros XML de
definición de beans típicos de Spring y las ventajas del uso del patrón DependencyInjection.

Como se comentó anteriormente, adicionalmente Spring Security permite una configuración de los
componentes mediante el uso de un namespace, el cual consiste básicamente en un fichero XML
que cumple un determinado esquema, el cuál está preparado para la configuración de los distintos
componentes de la solución de un modo sencillo.

Por tanto, lo único que se necesita para configurar los servicios de seguridad web es introducir la
siguiente configuración dentro del fichero XML de configuración:
Configuración de servicios de seguridad web

En el ejemplo se puede ver como se configura el mecanismo de autenticación basado en formulario.


En el caso que se quiera establecer un mecanismo de autenticación básico, únicamente sería
necesario introducir la etiqueta .

Dentro de la configuración, adicionalmente se puede ver como se pueden securizar urls mediante el
uso de la etiqueta . Básicamente esta etiqueta contiene el patrón de url que se quiere securizar y
una lista de roles que son necesarios para poder acceder al recurso. En el caso que se indiquen
varios roles, con que el usuario contenga uno de esos roles, sería suficiente para disponer de
permiso para dicha URL.

Dentro de este fichero de configuración se pueden configurar las siguientes grandes


funcionalidades:

 Funcionalidades remember-me las cuales darán soporte a permitir que el usuario pueda
guardar las credenciales en el navegador, y así no tener que volver a introducirlas en el
siguiente proceso de autenticación. Usa un soporte de cookies con aplicación de algoritmos
hash para la salvaguarda de la información de la credencial.
 Selección del canal de seguridad. Mediante el uso del atributo requires-channel dentro
de la etiqueta se puede exigir que determinadas URL’s sean seguras dentro de la aplicación.
Spring Security hace las oportunas redirecciones que sean necesarias para el cambio de
canal.
 Gestión de la sesión.
o Control de los timeouts de sesión. Se le puede indicar una página cuando se
realice una petición de una sesión que está invalidada.
o Control de la sesión concurrente. Es posible controlar el número de sesiones
activas para un mismo usuario. Esto supone una protección contra el ataque de
fijación de sesión: http://en.wikipedia.org/wiki/Session_fixation
 Soporte para OpenID

Desde el punto de vista de la arquitectura, Spring Security mantiene una cadena de filtros, cada
uno de los cuales da cabida a una funcionalidad dentro de los procesos de autenticación y
autorización entre cada petición y respuesta. Es posible modificar y extender la cadena de filtros
para ajustarse a las necesidades particulares de cada aplicación. Así por ejemplo por destacar
algunos mencionar los siguientes filtros:

 FilterSecurityInterceptor. Es el encargado de manejar la seguridad de los recursos HTTP.


Básicamente es el que maneja los elementos definidos anteriormente en el namespace.
 ExceptionTranslationFilter. Es el encarga de manejar las excepciones lanzadas por los
interceptores de seguridad y proveer la respuesta HTTP correspondiente.
 SecurityContextPersistenceFilter: Es el responsable de guardar el contexto de seguridad
entre peticiones. Básicamente el contexto de seguridad es guardado a nivel de sesión.
Cadena de filtros

Como se puede ver en la figura, existen numerosos interceptores en la cadena, pero no vamos a
comentar todos ellos en este post, con el objetivo de disponer de una visión más global de la
librería. Para más detalle sobre dichos interceptores consultar la guía de referencia de Spring
Security.

En definitiva, toda la cadena de filtros es creada y aislada del programador mediante el uso del
namespace. No obstante, y como se ha comentado antes, es posible modificar y extender la
cadena de filtros para poder adaptarlo a las necesidades particulares de la aplicación.

A continuación detallaremos el módulo de autorización de Spring Security.

Autorización en SpringSecurity

A continuación se presenta un diagrama de clases donde se define la arquitectura del módulo de


autorización en Spring Security.

Autorización Spring Security

Como se puede ver en la figura, el interfaz central es AbstractSecurityInterceptor. Básicamente es


una clase abstracta que representa las capacidades de autorización básicas. Como se puede ver en
la figura los objetos que se pueden securizar dentro de Spring Security son peticiones HTTP
(FilterSecurityInterceptor) e invocaciones a métodos, que se pueden realizar mediante
MethodSecurityInterceptor y AspectJSecurityInterceptor.
Este interceptor delega en el interfaz AccessDecisionManager la decisión de autorización final.
Este interfaz implementa un método decide que básicamente recibe un objeto Authentication
representando al principal que accede a la petición, un objeto seguro (url o ejecución de método) y
una lista de atributos con metadatos de seguridad (básicamente la lista de roles para los que se les
puede dar acceso al recurso).

A continuación veamos el diseño definido para el componente AccessDecisionManager:

AccessDecisionManager

Como se puede ver en la figura, el sistema de autorización de Spring Security está basado en un
sistema de Votos. Concretamente SpringSecurity viene con tres implementaciones de
AccessDecisionManager:

 AffirmativeBased: En el caso de recibir un sólo voto positivo, se le da acceso al recurso


protegido.Se permite controlar el comportamiento en el caso que todos los votos son de
abstención.
 ConsensusBased: Será necesario que haya más votos positivos que negativos para dar
acceso al recurso protegido. Se permite controlar el comportamiento en el caso que todos
los votos son de abstención.
 UnanimousBased: Es necesario que todos los votos sean positivos para dar acceso al
recurso protegido. Se permite controlar el comportamiento en el caso que todos los votos
son de abstención.

Como se puede ver en la figura los componentes AccessDecisionManager usan


AccessDecisionVoter. En concreto en Spring Security vienen dos implementaciones de
AccessDecisionVoter:

 RoleVoter: Este componente simplemente comprueba si para cada rol especificado para
proteger al recurso protegido lo presenta el principal que realiza la petición. En tal caso
emite un voto positivo. (Revisar el componente ). En el caso que el principal no tenga el rol
el componente realizará un voto negativo. En concreto para el caso del componente se
presenta un AffirmativeBased AccessDecisionManager, con lo que con que el principal
disponga de un rol de los especificados en la lista, se procederá a dar permiso al recurso
protegido (en este caso la URL).
 AuthenticatedVoter. Este componente permite diferenciar entre acceso anónimo al
recurso, completamente autenticado u autenticado mediante mecanismos remember-me
(IS_AUTHENTICATED:ANONYMOUS, IS_AUTHENTICATED_REMEMBERED,
IS_AUTHENTICATED_FULLY). Así por ejemplo en el ejemplo expuesto anteriormente, se le
permitía a usuarios anónimos acceder a la página de autenticación del usuario. Esto
normalmente suele ser necesario para aquellas páginas que necesitan tener un
comportamiento diferente para usuarios autenticados, de usuarios no autenticad

Todos los componentes del módulo de autorización de SpringSecurity permiten ser


extendidos para proveer mecanismos de autorización más sofisticados.

En resumen, para securizar recursos HTTP, el sistema de votos aplica una lógica OR, de tal manera
que con que el principal disponga de al menos uno de los roles especificado en la lista de roles
asociados al recurso protegido, el AccessDecisionManager se procederá a dar acceso a dicho
recurso protegido.

Adicionalmente, SpringSecurity permite el securizar invocaciones a métodos, comúnmente llamado


seguridad a nivel de capa de servicio. Esto permitirá que dispongamos de mecanismos de
autorización de invocaciones de componentes que forman la capa de servicio, no quedándonos
únicamente en la securización de componentes de la capa web de la aplicación.

Seguridad de la capa de servicio

Existen cuatro formas distintas de securizar las ejecuciones de métodos dentro de Spring Security:

 Configuración de seguridad a nivel global (uso del namespace)


 Configuración de seguridad usando el componente MethodSecurityInterceptor
 Configuración de seguridad basada en anotaciones (JSR-250 ó SpringSecurity).
 Configuración de seguridad a nivel de bean

A continuación se muestra un ejemplo de cada una de ellas.

Configuración de seguridad a nivel global (namespace)

Esta opción permite una securización centralizada de todos los métodos de la capa de servicio.
Adicionalmente presenta una expresión AspectJ de definición del pointcut, el cual permite aplicar
de manera flexible seguridad a varios objetos. En el ejemplo expuesto se están securizando todos
los métodos del paquete com.mycompany que acaben por Service e independientemente del
número de parámetros que tenga el método.

MethodSecurityInterceptor

Otra opción posible, aunque las expresiones no son tan potentes como el caso de AspectJ.

Seguridad a nivel de bean


La principal desventaja de esta aproximación es que por cada bean es necesario indicar los
parámetros de seguridad necesarios a cada uno de los métodos. Es por tanto, una solución más
descentralizada y con más cantidad de configuración necesaria.

Seguridad a nivel de anotación

Directamente sobre la clase que se quiere securizar se introducen anotaciones específicas (propias
de Spring Security o las definidas por el estándar JSR-150). Es necesario dentro del namespace
configurar los atributos secured-annotations o jsr-250-annotations a “enabled” en el elemento mdel
namespace.

Con estas opciones, el nivel de seguridad disponible siempre es a nivel de rol (autoridad). Sin
embargo, Spring Security 3.o introduce un nuevo mecanismo mucho más potente que permite la
introducción de expresiones Spring-EL (nuevas en Spring 3.0) para securizar la invocación de
métodos. Con este modelo, lo que se permite es disponer de expresiones más completas para
definir la seguridad a nivel de método, existiendo la posibilidad de interactuar con los parámetros
de entrada. Así por ejemplo, con las expresiones Spring-EL, supongamos que disponemos de un
método de consulta de facturas de clientes. Resulta que dentro de los requisitos de seguridad de la
aplicación, se define que únicamente los administradores pueden imprimir facturas superiores a
5000 €.

Para este propósito Spring introduce las anotaciones @PreAuthorize, @PostAuthorize, @PreFilter y
@PostFilter . Para el ejemplo expuesto anteriormente, la anotación quedaría de la siguiente
manera:

@PreAuthorize(“hasRole(‘ADMIN’) and #factura.importe>5000″)

public void imprimir(Factura factura);

En cuanto a las anotaciones @PreFilter y @PostFilter se usan para filtrar elementos de una
colección antes o después de la ejecución del método. Pongamos un ejemplo, supongamos que de la
lista de Facturas devueltas por un método, se quieren filtrar aquellas que sean mayores de 5000€,
para esta funcionalidad sería necesario implementar una anotación @PostFilter indicando la
condición anteriormente definida.

Para finalizar nuestro recorrido por SpringSecurity, a continuación se define cómo SpringSecurity
mediante su sistema de control de acceso permite la securización de los objetos de dominio.

Seguridad de objetos de dominio mediante ACL

A veces es necesario securizar los propios objetos de dominio de la aplicación. En un supuesto


ejemplo de facturas, supongamos que queremos controlar el acceso para que cada usuario vea las
facturas de unos determinados clientes. Para ello, sería necesario introducir elementos de
seguridad en cada uno de los objetos de dominio. Considerando que los objetos de dominio pueden
ser potencialmente muy numerosos, las opciones con SpringSecurity que se abren son las
siguientes:

 Escribir los métodos de negocio, de tal manera que dentro de su implementación se


realicen las oportunas reglas de autorización sobre los objetos de dominio. La principal
desventaja de esta opción es que mezcla la propia lógica de negocio del dominio con la
lógica de seguridad de los mismos, lo cual ahonda en una falta de separación de conceptos
y una dificultad a la hora de realizar los procesos de testeo.
 Escribir un AccessDecisionVoter que fuerze la seguridad a partir de la lista de
GrantedAuthorities (permisos de aplicación) guardados en el objeto Authentication. Esta
opción necesitaría el crear un objeto GrantedAuthority por cada objeto de dominio que
queramos securizar. El problema, aunque conceptualmente es aceptable reside en la
escalabilidad de la solución, puesto que la cantidad de memoria necesaria para guardar los
GrantedAuthority es muy alta.
 Escribir un AccessDecisionVoter que se encarga de forzar la seguridad a partir de la
obtención directa de los objetos de dominio que se quieren securizar. Por tanto, el
componente AccessDecisionVoter dispondría de un objeto DAO para recuperar los datos de
los objetos de dominio. Sin embargo, esto obliga a que haya un doble acceso a BBDD por
invocación de método que hace que el rendimiento no sea el más idóneo.

Por tanto, para solucionar esta problemática, SpringSecurity viene con un esquema de tablas (4
tablas en total) que permiten guardar los objetos de dominio, los permisos de la aplicación y el
cruce entre los distintos permisos y objetos de dominio necesarios para implementar la seguridad.
Por defecto, el nivel de permisos que viene con la solución son: CREATE, DELETE, READ, WRITE y
ADMIN, aunque es sencillo implementar nuevos permisos.

Adicionalmente, el sistema de control de acceso proporcionado por SpringSecurity viene con un


conjunto de objetos que se encargan por un lado de abstraerte del modelo de datos subyacente,
y por otro lado ofrece la lógica de servicio que permite la obtención de los permisos sobre los
objetos de un modo eficiente, puesto que la cantidad de información manejada para implementar
esta funcionalidad es potencialmente alta. El sistema está integrado con el componente EHCache, lo
que permite disponer de mecanismos de caché que optimizan la ejecución de consultas, así como
mecanismos tales como vistas materializadas, consultas jerárquicas y similares capacidades para el
aumento del rendimiento de la solución.

A continuación se plantea un ejemplo de un método de lógica de negocio que es securizado usando


las expresiones introducidas en el apartado anterior, y que permite filtrar el conjunto de objetos de
dominio devuelto por el método, restringiendo los elementos de la colección, para las que el
usuario tiene permiso de lectura y administración. En este caso, el sistema de ACL se encargará de
filtrar de todos los elementos de la colección devueltos por el método, sólo aquellos con permisos
de lectura y administración.

Listas de control de acceso

Para más información de cómo se configura el módulo ACL, consultar la guía de referencia de
Spring Security o el ejemplo Contacts que viene incluido dentro del código de SpringSecurity. El
propósito de este post es comentar las posibilidades que presenta SpringSecurity sin entrar en los
detalles de configuración más específicos.

Conclusiones

Como se ha podido ver a lo largo del artículo, SpringSecurity proporciona una librería con gran
capacidad para la implementación de los servicios de autenticación y autorización de una
aplicación. Con una configuración mínima es posible realizar la autenticación de la aplicación en
BBDD, LDAP, integración con CAS para Single Sign On, etc… Asimismo mediante mecanismos
declarativos es posible la securización de los recursos de una aplicación web, con la potencia que
dan las expresiones AspectJ de definición de pointcuts. Asimismo todas las funcionalidades de
remember-me y de gestión de usuarios anónimos está implicita dentro de la solución, con lo que
prácticamente no es necesario implementar componentes para dar cabida a dichas funcionalidades.

Mediante mecanismos de programación orientada a aspectos, se pueden securizar invocaciones a


métodos de la capa de servicio, y con el nuevo soporte de expresiones Spring-EL se permite, incluso
implementar políticas de seguridad específicas del dominio.
Finalmente, y para dar soporte a la securización de objetos del dominio, SpringSecurity viene con
todo el soporte necesario para evitar implementar soluciones específicas a las aplicaciones y
garantizando que el rendimiento de la aplicación es óptimo. Y todo ello aderezado con la excelencia
en la codificación de las clases que forman parte de la solución y un diseño espectacular muy
modular que permite la extensibilidad de cualquier funcionalidad dentro del framework de manera
muy sencilla.

En definitiva, enhorabuena de nuevo al equipo de Spring Framework, realizando una solución que
considero de referencia dentro de la tecnología Java para la seguridad de aplicaciones Java.

A los lectores de este post, agradecer que introduzcan todos los comentarios que crean
convenientes con el objeto de que el artículo sea lo más completo y útil posible, para que por lo
menos, alguien que no conociera SpringSecurity pueda tener un primer contacto con él y conozca
las posibilidades de esta magnífica librería.

También podría gustarte