Esta sección analiza la arquitectura de alto nivel de Spring Security en aplicaciones basadas en servlets.
Una breve descripción de los filtros
El soporte de servlet de Spring Security se basa en
instancias de servlet Filter
, por lo que es útil observar primero la función de Filter
en
general. La siguiente figura muestra una estructura en capas típica de controladores para una única solicitud HTTP.
![](https://cdn.codegym.cc/images/article/9e804fc3-08e4-48d9-a91e-70414583d5b8/256.jpeg)
El
cliente envía una solicitud a la aplicación y el contenedor crea un FilterChain
, que contiene
instancias de un Filter
y un Servlet
que deben procesar un HttpServletRequest
según la ruta del URI de solicitud. En una aplicación Spring MVC, Servlet
es una instancia de DispatcherServlet
.
Sólo un Servlet
puede manejar una HttpServletRequest
y una
HttpServletResponse
. Sin embargo, puede utilizar más de un filtro
para:
evitar llamadas al
filtro
o al descendenteservlet
. En este caso,Filter
normalmente registraHttpServletResponse
.Cambios en
HttpServletRequest
oHttpServletResponse
utilizado por los subsiguientesFilter
yServlet
El poder de Filter
depende de FilterChain
, que se le pasa.
FilterChain
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// hacer algo antes de ejecutar el resto de la cadena de aplicaciones
chain.doFilter(request, response); // invocar el resto de la aplicación
// hacer algo después de ejecutar el resto de la aplicación
}
fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
// hacer algo antes de ejecutar el resto de la aplicación
chain.doFilter(request, response); // invocar el resto de la aplicación
// hacer algo después el resto de la aplicación se ha ejecutado
}
Porque el Filtro
solo afecta al subyacente Filtro
y Servlet
, el
orden en el que se llama a cada Filter
es extremadamente importante.
DelegatingFilterProxy
Spring proporciona un implementación de Filter
titulado DelegatingFilterProxy
, que le permite establecer un puente entre el ciclo de
vida de un contenedor de servlets y ApplicationContext
de Spring. El contenedor de servlets le permite
registrar instancias Filter
utilizando sus propios estándares, pero no conoce los beans definidos por
Spring. DelegatingFilterProxy
se puede registrar a través de mecanismos de contenedor de servlets
estándar, pero delega todo el trabajo al Spring Bean que implementa Filter
.
Así es como DelegatingFilterProxy
se utiliza encaja en un esquema con instancias Filter
y
FilterChain
.
![](https://cdn.codegym.cc/images/article/9f02cafc-c0e6-456f-a7d3-917f21a01d1f/256.jpeg)
DelegatingFilterProxy
busca Bean Filter0
en ApplicationContext
y luego llama a Bean Filter0. El pseudocódigo para DelegatingFilterProxy
se muestra a continuación.
DelegatingFilterProxy
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// En modo diferido, obtenemos el filtro que se registró como Spring bean
// Para el ejemplo en DelegatingFilterProxy, el delegado es la instancia Bean Filter0
Filter delegate = getFilterBean(someBeanName);
// delega el trabajo al Spring Bean delegado.doFilter(solicitud, respuesta);
}
fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
// En modo diferido, obtenemos el filtro que se registró como Spring Bean
// Para el ejemplo en DelegatingFilterProxy, el delegado es una instancia de Bean Filter0
val delegate: Filter = getFilterBean(someBeanName)
// delegar el trabajo con Spring Bean delegado.doFilter(solicitud, respuesta)
}
Otra ventaja de DelegatingFilterProxy
es que le permite diferir la búsqueda de instancias
de beans Filter
. Esto es importante porque el contenedor necesita registrar instancias
Filter
antes de ejecutarlo. Sin embargo, Spring normalmente usa ContextLoaderListener
para
cargar Spring beans, lo que solo ocurre después de que se hayan registrado las instancias Filter
.
FilterChainProxy
Las instalaciones de servlet en Spring Security están contenidas en
FilterChainProxy
. FilterChainProxy
es un Filter
especializado proporcionado
por Spring Security que le permite delegar autoridad a múltiples instancias de Filter
a través de
SecurityFilterChain
. Dado que FilterChainProxy
es un bean, generalmente está incluido en
DelegatingFilterProxy.
![](https://cdn.codegym.cc/images/article/c8845bc7-7293-46e7-9c40-e06ca170869b/512.jpeg)
SecurityFilterChain
SecurityFilterChain
es utilizado por FilterChainProxy
para determinar qué Filter
de Spring Security debe llamarse para una solicitud determinada.
![](https://cdn.codegym.cc/images/article/5e5fbf12-3ca5-4520-9f1a-79fed6a641c3/512.jpeg)
Los
filtros de seguridad en SecurityFilterChain
suelen ser beans, pero están registrados en FilterChainProxy
en lugar de DelegatingFilterProxy
. FilterChainProxy
proporciona varias ventajas sobre
el registro directo con el contenedor de servlets o DelegatingFilterProxy. Primero, proporciona el punto de
partida para todo el soporte de servlets en Spring Security. Por este motivo, si está intentando solucionar
problemas de compatibilidad con servlets de Spring Security, un buen lugar para comenzar es agregar un punto de
depuración a FilterChainProxy
.
En segundo lugar, porque FilterChainProxy
es
fundamental para el uso de Spring Security, puede realizar tareas que no se consideran opcionales. Por ejemplo,
limpia SecurityContext
para evitar pérdidas de memoria. También utiliza HttpFirewall
de
Spring Security para proteger las aplicaciones de ciertos tipos de ataques.
También proporciona mayor
flexibilidad para determinar cuándo llamar a SecurityFilterChain
. En un contenedor de servlets, las
instancias Filter
se llaman basándose únicamente en la URL. Sin embargo, FilterChainProxy
puede determinar la llamada basándose en cualquier cosa en HttpServletRequest
usando la interfaz RequestMatcher
.
De hecho, FilterChainProxy
se puede utilizar para determinar qué SecurityFilterChain
se debe utilizar. Esto le permite proporcionar una configuración completamente separada para diferentes partes de su
aplicación.
![](https://cdn.codegym.cc/images/article/44d4dade-4b63-462d-9b0a-82fb02ca8644/512.jpeg)
En la imagen con varios SecurityFilterChain, el FilterChainProxy
La
instancia decide qué SecurityFilterChain
debe usarse. Sólo se llamará al primer SecurityFilterChain
coincidente. Si se solicita la URL /api/messages/
, primero se comparará con el patrón SecurityFilterChain0
a través de /api/* *
, por lo que solo se llamará SecurityFilterChain0
, incluso
si también coincide con SecurityFilterChainn
. Si se solicita la URL
/messages/
, no se comparará con el patrón SecurityFilterChain0
a través de
/api/**
, por lo que FilterChainProxy
continuará iterando sobre cada SecurityFilterChain
.
Se supone que no se llamarán otras instancias de SecurityFilterChain
que coincidan con SecurityFilterChainn
.
Tenga en cuenta que en SecurityFilterChain0
solo se configuran tres instancias de
Filter
. Sin embargo, hay cuatro Filter
configurados en
SecurityFilterChainn
. Es importante tener en cuenta que cada
SecurityFilterChain
puede ser única y configurarse de forma aislada. De hecho, SecurityFilterChain
puede tener cero instancias de Filter
si la aplicación quiere que Spring Security ignore ciertas
solicitudes.
Filtros de seguridad
Los filtros Spring Security se agregan a FilterChainProxy a
través de la API SecurityFilterChain. El orden de las instancias de Filter
es importante. Normalmente
no es necesario conocer el orden de Filter
en Spring Security. Sin embargo, en algunos casos es útil
saber en qué orden están.
La siguiente es una lista ordenada completa de los filtros Spring Security:
ForceEagerSessionCreationFilter
ChannelProcessingFilter
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
CsrfFilter
LogoutFilter
OAuth2AuthorizationRequestRedirectFilter
Saml2WebSsoAuthenticationRequestFilter
X509AuthenticationFilter
AbstractPreAuthenticatedProcessingFilter
CasAuthenticationFilter
OAuth2LoginAuthenticationFilter
Saml2WebSsoAuthenticationFilter
Nombre de usuarioContraseñaAuthenticationFilter
OpenIDAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
ConcurrentSessionFilter
DigestAuthenticationFilter
BearerTokenAuthenticationFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
JaasApiIntegrationFilter
RememberMeAuthenticationFilter
AnonymousAuthenticationFilter
OAuth2AuthorizationCodeGrantFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
SwitchUserFilter
Manejo de excepciones de seguridad
ExceptionTranslationFilter
permite la conversión AccessDeniedException
y AuthenticationException
en las respuestas HTTP.
ExceptionTranslationFilter
se agrega a FilterChainProxy en calidad de uno de los filtros de seguridad.
![](https://cdn.codegym.cc/images/article/a38c12b1-2fb2-46b6-a706-cababcf33ff4/512.jpeg)
1 El primer
ExceptionTranslationFilter
accede aFilterChain.doFilter(solicitud, respuesta)
para llamar al resto de la aplicación.2 Si el usuario no está autenticado o se produce una
AuthenticationException
ocurre, luego ejecute procedimiento de autenticación.TheSecurityContextHolder se borra
HttpServletRequest
se guarda en el destinoSolicitarCaché
. Una vez que el usuario se haya autenticado correctamente, se utilizaráRequestCache
para reproducir la solicitud original.AuthenticationEntryPoint
se utilizará para solicitar credenciales de datos del cliente. Por ejemplo, podría redirigir a una página de inicio de sesión o enviar un encabezadoWWW-Authenticate
.
3 De lo contrario, si se produce
AccessDeniedException
, se denegará el acceso.AccessDeniedHandle
r
se llama para manejar la denegación de acceso.
Si la aplicación no genera una AccessDeniedException
o una
AuthenticationException
, entonces el ExceptionTranslationFilter
no hace nada.
El pseudocódigo para ExceptionTranslationFilter
se parece a esto:
try {
filterChain.doFilter(request, response);
} catch (AccessDeniedException | AuthenticationException ex) {
if (!authenticated || ex instanceof AuthenticationException) {
startAuthentication();
} else {
accessDenied();
}
}
- De la breve descripción de las instancias de
Filter
, puede recordar que llamar aFilterChain.doFilter(solicitud, respuesta)
es equivalente a llamar al resto de la aplicación. significa que si otra parte de la aplicación (por ejemplo,FilterSecurityInterceptor
o método de seguridad) genera unaAuthenticationException
oAccessDeniedException
, entonces esas excepciones serán detectadas y manejadas. en esta etapa. - Si el usuario no está autenticado o se genera una
AuthenticationException
, entonces ejecute el procedimiento de autenticación. - De lo contrario se denegará el acceso