Me doy cuenta de que la seguridad de Spring se basa en una cadena de filtros, que interceptará la solicitud, detectará (ausencia de) autenticación, redirigirá al punto de entrada de autenticación o pasará la solicitud al servicio de autorización y, finalmente, dejará que la solicitud llegue al servlet o arroje una excepción de seguridad (no autenticado o no autorizado). DelegatingFitlerProxy pega estos filtros juntos. Para realizar sus tareas, estos servicios de acceso de filtro, como UserDetailsService y AuthenticationManager .
Los filtros clave en la cadena son (en el orden)
- SecurityContextPersistenceFilter (restaura la autenticación de JSESSIONID)
- UsernamePasswordAuthenticationFilter (realiza la autenticación)
- ExceptionTranslationFilter (captura excepciones de seguridad de FilterSecurityInterceptor)
- FilterSecurityInterceptor (puede arrojar excepciones de autenticación y autorización)
Estoy confundido sobre cómo se usan estos filtros. ¿Es que para el inicio de sesión proporcionado por la primavera, UsernamePasswordAuthenticationFilter solo se usa para / login , y los últimos filtros no? ¿El elemento de espacio de nombres de inicio de sesión configura automáticamente estos filtros? ¿Cada solicitud (autenticada o no) llega a FilterSecurityInterceptor para la URL sin inicio de sesión?
¿Qué sucede si deseo asegurar mi API REST con JWT-token , que se recupera del inicio de sesión? Debo configurar dos http
etiquetas de configuración de espacio de nombres , ¿derechos? Uno para / iniciar sesión con UsernamePasswordAuthenticationFilter
, y otro para URL de REST, con personalizado JwtAuthenticationFilter
.
¿La configuración de dos http
elementos crea dos springSecurityFitlerChains
? Está UsernamePasswordAuthenticationFilter
desactivado por defecto, hasta que declare form-login
? ¿Cómo lo reemplazo SecurityContextPersistenceFilter
con un filtro que se obtendrá Authentication
de los existentes en JWT-token
lugar de JSESSIONID
?
fuente
Respuestas:
La cadena de filtros de seguridad Spring es un motor muy complejo y flexible.
Mirando la documentación actual de la versión estable 4.2.1 , sección 13.3 Orden de filtros , puede ver toda la organización de filtros de la cadena de filtros:
Ahora, intentaré continuar con sus preguntas una por una:
Una vez que esté configurando una
<security-http>
sección, para cada una debe proporcionar al menos un mecanismo de autenticación. Este debe ser uno de los filtros que coinciden con el grupo 4 en la sección 13.3 Orden de filtros de la documentación de Spring Security que acabo de mencionar.Esta es la seguridad mínima válida: elemento http que se puede configurar:
Simplemente, estos filtros se configuran en el proxy de la cadena de filtros:
Nota: Los obtengo creando un RestController simple que @Autowires FilterChainProxy y devuelve su contenido:
Aquí podríamos ver que solo al declarar el
<security:http>
elemento con una configuración mínima, se incluyen todos los filtros predeterminados, pero ninguno de ellos es del tipo Autenticación (4to grupo en la sección 13.3 Orden de filtros). Entonces, en realidad significa que con solo declarar elsecurity:http
elemento, SecurityContextPersistenceFilter, ExceptionTranslationFilter y FilterSecurityInterceptor se configuran automáticamente.De hecho, se debe configurar un mecanismo de procesamiento de autenticación, e incluso el procesamiento de beans de espacio de nombres de seguridad reclama eso, arrojando un error durante el inicio, pero se puede omitir agregando un atributo de entrada-punto-referencia en
<http:security>
Si agrego un básico
<form-login>
a la configuración, de esta manera:Ahora, el filterChain será así:
Ahora, estos dos filtros org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter y org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter se crean y configuran en FilterChainProxy.
Entonces, ahora, las preguntas:
Sí, se utiliza para intentar completar un mecanismo de procesamiento de inicio de sesión en caso de que la solicitud coincida con la URL de UsernamePasswordAuthenticationFilter. Esta url se puede configurar o incluso cambiar su comportamiento para que coincida con cada solicitud.
También podría tener más de un mecanismo de procesamiento de autenticación configurado en el mismo FilterchainProxy (como HttpBasic, CAS, etc.).
No, el elemento form-login configura UsernamePasswordAUthenticationFilter, y en caso de que no proporcione una URL de página de inicio de sesión, también configura org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter, que termina en un inicio de sesión simple autogenerado página.
Los otros filtros se configuran automáticamente de forma predeterminada simplemente creando un
<security:http>
elemento sinsecurity:"none"
atributo.Cada solicitud debe llegar a ella, ya que es el elemento que se encarga de si la solicitud tiene los derechos para llegar a la URL solicitada. Pero algunos de los filtros procesados antes podrían detener el procesamiento de la cadena de filtros simplemente no llamando
FilterChain.doFilter(request, response);
. Por ejemplo, un filtro CSRF podría detener el procesamiento de la cadena de filtros si la solicitud no tiene el parámetro csrf.No, no estás obligado a hacerlo de esta manera. Puede declarar ambos
UsernamePasswordAuthenticationFilter
y elJwtAuthenticationFilter
en el mismo elemento http, pero depende del comportamiento concreto de cada uno de estos filtros. Ambos enfoques son posibles, y cuál elegir finalmente depende de sus propias preferencias.Sí, eso es verdad
Sí, puedes verlo en los filtros generados en cada una de las configuraciones que publiqué
Puede evitar SecurityContextPersistenceFilter, simplemente configurando la estrategia de sesión en
<http:element>
. Solo configúrelo así:<security:http create-session="stateless" >
O, en este caso, podría sobrescribirlo con otro filtro, de esta manera dentro del
<security:http>
elemento:EDITAR:
Esto finalmente depende de la implementación de cada filtro en sí, pero es cierto el hecho de que los últimos filtros de autenticación al menos pueden sobrescribir cualquier autenticación previa que eventualmente haya hecho los filtros anteriores.
Pero esto no necesariamente sucederá. Tengo algunos casos de producción en servicios REST seguros donde utilizo un tipo de token de autorización que se puede proporcionar como un encabezado Http o dentro del cuerpo de la solicitud. Así que configuro dos filtros que recuperan ese token, en un caso del encabezado Http y el otro del cuerpo de la solicitud de la propia solicitud de descanso. Es cierto el hecho de que si una solicitud http proporciona ese token de autenticación como encabezado Http y dentro del cuerpo de la solicitud, ambos filtros intentarán ejecutar el mecanismo de autenticación delegándolo al administrador, pero podría evitarse fácilmente simplemente verificando si la solicitud es ya autenticado justo al comienzo del
doFilter()
método de cada filtro.Tener más de un filtro de autenticación está relacionado con tener más de un proveedor de autenticación, pero no lo fuerce. En el caso que expuse antes, tengo dos filtros de autenticación, pero solo tengo un proveedor de autenticación, ya que ambos filtros crean el mismo tipo de objeto de autenticación, por lo que en ambos casos el administrador de autenticación lo delega al mismo proveedor.
Y frente a esto, yo también tengo un escenario en el que publico solo un UsernamePasswordAuthenticationFilter pero las credenciales del usuario pueden estar contenidas en DB o LDAP, por lo que tengo dos proveedores de soporte UsernamePasswordAuthenticationToken, y AuthenticationManager delega cualquier intento de autenticación del filtro a los proveedores secuencialmente para validar las credenciales.
Entonces, creo que está claro que ni la cantidad de filtros de autenticación determina la cantidad de proveedores de autenticación ni la cantidad de proveedores determina la cantidad de filtros.
No examiné cuidadosamente este filtro antes, pero después de su última pregunta, he estado revisando su implementación y, como generalmente en Spring, casi todo se puede configurar, extender o sobrescribir.
Los SecurityContextPersistenceFilter delegados en un SecurityContextRepository aplicación la búsqueda de los SecurityContext. Por defecto, se utiliza un HttpSessionSecurityContextRepository , pero esto podría cambiarse utilizando uno de los constructores del filtro. Por lo tanto, puede ser mejor escribir un SecurityContextRepository que se ajuste a sus necesidades y simplemente configurarlo en SecurityContextPersistenceFilter, confiando en su comportamiento comprobado en lugar de comenzar a hacer todo desde cero.
fuente
No qualifying bean of type 'org.springframework.security.web.FilterChainProxy' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
No, se
UsernamePasswordAuthenticationFilter
extiendeAbstractAuthenticationProcessingFilter
, y esto contiene unRequestMatcher
, eso significa que puede definir su propia url de procesamiento, este filtro solo maneja lasRequestMatcher
coincidencias con la url de solicitud, la url de procesamiento predeterminada es/login
.Los filtros posteriores aún pueden manejar la solicitud, si se
UsernamePasswordAuthenticationFilter
ejecutachain.doFilter(request, response);
.Más detalles sobre los montadores centrales
UsernamePasswordAuthenticationFilter
es creado por<form-login>
, estos son alias de filtro estándar y pedidosDepende de si los instaladores anteriores tienen éxito, pero
FilterSecurityInterceptor
normalmente es el último instalador.Sí, cada fitlerChain tiene una
RequestMatcher
, siRequestMatcher
coincide con la solicitud, la solicitud será manejada por los instaladores en la cadena de instaladores.El valor predeterminado
RequestMatcher
coincide con todas las solicitudes si no configura el patrón, o puede configurar la url específica (<http pattern="/rest/**"
).Si quieres saber más sobre los fitlers, creo que puedes consultar el código fuente en seguridad de primavera.
doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
fuente
Spring Security es un marco basado en filtros, planta un WALL (HttpFireWall) antes de su aplicación en términos de filtros proxy o beans gestionados por Spring. Su solicitud debe pasar por varios filtros para llegar a su API.
Secuencia de ejecución en Spring Security
WebAsyncManagerIntegrationFilter
Proporciona integración entre SecurityContext y el WebAsyncManager de Spring Web.SecurityContextPersistenceFilter
Este filtro solo se ejecutará una vez por solicitud, rellena el SecurityContextHolder con la información obtenida del SecurityContextRepository configurado antes de la solicitud y la almacena de nuevo en el repositorio una vez que la solicitud se ha completado y borra el contenedor de contexto.La solicitud se verifica para la sesión existente. Si hay una nueva solicitud, se creará SecurityContext; de lo contrario, si la solicitud tiene sesión, el contexto de seguridad existente se obtendrá del repositorio .
HeaderWriterFilter
Implementación de filtro para agregar encabezados a la respuesta actual.LogoutFilter
Si la solicitud es url/logout
(para la configuración por defecto) o si mathces solicitud de URLRequestMatcher
configurados deLogoutConfigurer
entoncesLogoutConfigurer
/
sesión o url de éxito de cierre de sesión configurada o invoca logoutSuccessHandler configurado.UsernamePasswordAuthenticationFilter
HTTP POST
) por defecto/login
o partidos.loginProcessingUrl()
configurados enFormLoginConfigurer
entoncesUsernamePasswordAuthenticationFilter
la autenticación intentos.usernameParameter(String)
,passwordParameter(String)
..loginPage()
anula los valores predeterminadosAuthentication
objeto (UsernamePasswordAuthenticationToken
o cualquier implementaciónAuthentication
en caso de su filtro de autenticación personalizado).authenticationManager.authenticate(authToken)
será invocadoAuthenticationProvider
método de autenticación que intente con todos los proveedores de autenticación y verifique cualquiera de los proveedores de autenticaciónsupports
authToken / objeto de autenticación, se utilizará el proveedor de autenticación compatible para la autenticación. y devuelve el objeto de autenticación en caso de autenticación exitosa, de lo contrario, se lanzaAuthenticationException
.authenticationSuccessHandler
se invocará, se redireccionará a la URL de destino configurada (el valor predeterminado es/
)SecurityContextHolderAwareRequestFilter
, si lo está utilizando para instalar un HttpServletRequestWrapper consciente de Spring Security en su contenedor de servletAnonymousAuthenticationFilter
Detecta si no hay un objeto de autenticación en SecurityContextHolder, si no se encuentra ningún objeto de autenticación, crea unAuthentication
objeto (AnonymousAuthenticationToken
) con autorización otorgadaROLE_ANONYMOUS
. AquíAnonymousAuthenticationToken
facilita la identificación de solicitudes posteriores de usuarios no autenticados.ExceptionTranslationFilter
, para detectar cualquier excepción de Spring Security para que se pueda devolver una respuesta de error HTTP o se pueda iniciar un AuthenticationEntryPoint apropiadoFilterSecurityInterceptor
Habrá
FilterSecurityInterceptor
casi el último en la cadena de filtros que obtiene el objeto de autenticaciónSecurityContext
y obtiene la lista de autoridades (roles otorgados) y tomará la decisión de permitir que esta solicitud llegue al recurso solicitado o no, la decisión se toma haciendo coincidir con lo permitidoAntMatchers
configurado enHttpSecurityConfiguration
.Considere las excepciones 401-No autorizadas y 403-Prohibidas. Estas decisiones se tomarán al final de la cadena de filtros.
Nota: Solicitud de Usuario fluye no sólo en filtros anteriormente mencionado, pero hay otros filtros también que no se muestran aquí (.
ConcurrentSessionFilter
,RequestCacheAwareFilter
,SessionManagementFilter
...)Será diferente cuando se utiliza el filtro de autenticación personalizado en lugar de
UsernamePasswordAuthenticationFilter
.Será diferente si configura el filtro de autenticación JWT y omite
.formLogin() i.e, UsernamePasswordAuthenticationFilter
que se convertirá en un caso completamente diferente.Solo para referencia. Filtros en spring-web y spring-security
Nota: consulte el nombre del paquete en la imagen , ya que hay algunos otros filtros de orm y mi filtro implementado personalizado.
¿También puede referirse a la forma
más común de autenticar una aplicación web moderna?
diferencia entre autenticación y autorización en el contexto de Spring Security?
fuente