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.
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
filtroo al descendenteservlet. En este caso,Filternormalmente registraHttpServletResponse.Cambios en
HttpServletRequestoHttpServletResponseutilizado por los subsiguientesFilteryServlet
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.
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.
SecurityFilterChain
SecurityFilterChain es utilizado por FilterChainProxy para determinar qué Filter de Spring Security debe llamarse para una solicitud determinada.
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.
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:
ForceEagerSessionCreationFilterChannelProcessingFilter
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
CsrfFilter
LogoutFilter
OAuth2AuthorizationRequestRedirectFilter
Saml2WebSsoAuthenticationRequestFilter
X509AuthenticationFilter
AbstractPreAuthenticatedProcessingFilter
CasAuthenticationFilter
OAuth2LoginAuthenticationFilter
Saml2WebSsoAuthenticationFilter
Nombre de usuarioContraseñaAuthenticationFilterOpenIDAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
ConcurrentSessionFilter
DigestAuthenticationFilterBearerTokenAuthenticationFilter
BasicAuthenticationFilterRequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
JaasApiIntegrationFilter
RememberMeAuthenticationFilter
AnonymousAuthenticationFilter
OAuth2AuthorizationCodeGrantFilter
SessionManagementFilter
ExceptionTranslationFilterFilterSecurityInterceptorSwitchUserFilter
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.
1 El primer
ExceptionTranslationFilteraccede aFilterChain.doFilter(solicitud, respuesta)para llamar al resto de la aplicación.2 Si el usuario no está autenticado o se produce una
AuthenticationExceptionocurre, luego ejecute procedimiento de autenticación.TheSecurityContextHolder se borra
HttpServletRequestse guarda en el destinoSolicitarCaché. Una vez que el usuario se haya autenticado correctamente, se utilizaráRequestCachepara reproducir la solicitud original.AuthenticationEntryPointse 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.AccessDeniedHandlerse 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,FilterSecurityInterceptoro método de seguridad) genera unaAuthenticationExceptionoAccessDeniedException, 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
GO TO FULL VERSION