java - delegatingfilterproxy - spring filter
¿Cómo agregar una clase de filtro en Spring Boot? (15)
Aquí hay un ejemplo de mi clase de filtro personalizada:
package com.dawson.controller.filter;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class DawsonApiFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if (req.getHeader("x-dawson-nonce") == null || req.getHeader("x-dawson-signature") == null) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setContentType("application/json");
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "Required headers not specified in the request");
return;
}
chain.doFilter(request, response);
}
}
Y lo agregué a la configuración de arranque de Spring agregándolo a la clase de configuración de la siguiente manera:
package com.lyrahealth.configuration;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.dawson.controller.filter.DawsonApiFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@SpringBootApplication
public class ApplicationConfiguration {
@Bean
public FilterRegistrationBean dawsonApiFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new DawsonApiFilter());
// In case you want the filter to apply to specific URL patterns only
registration.addUrlPatterns("/dawson/*");
return registration;
}
}
Me pregunto si hay alguna anotación para una clase de Filter
(para aplicaciones web) en Spring Boot. Quizás @Filter
?
Quiero agregar un filtro personalizado en mi proyecto.
La Guía de referencia de Spring Boot mencionaba FilterRegistrationBean
, pero no estoy seguro de cómo usarlo.
Aquí hay un ejemplo de un método para incluir un filtro personalizado en una aplicación Spring Boot MVC. Asegúrese de incluir el paquete en un análisis de componentes:
package com.dearheart.gtsc.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
public class XClacksOverhead implements Filter {
public static final String X_CLACKS_OVERHEAD = "X-Clacks-Overhead";
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader(X_CLACKS_OVERHEAD, "GNU Terry Pratchett");
chain.doFilter(req, res);
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig arg0) throws ServletException {}
}
Desde Spring docs,
Contenedores de servlets incrustados: agregue un servlet, filtro o escucha a una aplicación
Para agregar un Servlet, Filtro o Servlet * Listener, proporcione una definición de @Bean .
P.ej:
@Bean
public Filter compressFilter() {
CompressingFilter compressFilter = new CompressingFilter();
return compressFilter;
}
Agregue esta configuración @Bean
a su clase @Configuration
y el filtro se registrará al inicio.
También puede agregar Servlets, Filters y Listeners utilizando el escaneo classpath,
Las clases anotadas @WebServlet, @WebFilter y @WebListener se pueden registrar automáticamente con un contenedor de servlet incorporado anotando una clase @Configuration con @ServletComponentScan y especificando los paquetes que contienen los componentes que desea registrar. De forma predeterminada, @ServletComponentScan escaneará desde el paquete de la clase anotada.
Es más un consejo que una respuesta, pero si está utilizando Spring MVC en su aplicación web, la buena idea es utilizar Spring HandlerInterceptor en lugar de Filter
Puede hacer el mismo trabajo, pero también: puede funcionar con ModelAndView. Se pueden llamar sus métodos antes y después del procesamiento de la solicitud o después de completar la solicitud.
- Se puede probar fácilmente
1 Implementa la interfaz HandlerInterceptor y agrega una anotación @Component a tu clase
@Component
public class SecurityInterceptor implements HandlerInterceptor {
private static Logger log = LoggerFactory.getLogger(SecurityInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.getSession(true);
if(isLoggedIn(request))
return true;
response.getWriter().write("{/"loggedIn/":false}");
return false;
}
private boolean isLoggedIn(HttpServletRequest request) {
try {
UserSession userSession = (UserSession) request.getSession(true).getAttribute("userSession");
return userSession != null && userSession.isLoggedIn();
} catch(IllegalStateException ex) {
return false;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
2 Configura tu interceptor
@Configuration
public class WebConfig implements WebMvcConfigurer {
private HandlerInterceptor securityInterceptor;
@Autowired
public void setSecurityInterceptor(HandlerInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(securityInterceptor).addPathPatterns("/**").excludePathPatterns("/login", "/logout");
}
}
Hay tres maneras de agregar su filtro,
- Anota tu filtro con uno de los estereotipos de Spring como
@Component
- Registre un
@Bean
con tipo deFilter
en Spring@Configuration
- Registre un
@Bean
conFilterRegistrationBean
type en Spring@Configuration
Ya sea el # 1 o el # 2, si quieres que tu filtro se aplique a todas las solicitudes sin personalización, usa el # 3 en caso contrario. No es necesario que especifique que el análisis de componentes para el # 1 funcione siempre que coloque su clase de filtro en el mismo SpringApplication
o en el de su clase SpringApplication
. Para el n. ° 3, el uso junto con el n. ° 2 solo es necesario cuando desea que Spring administre su clase de filtro, como por ejemplo tener dependencias auto cableadas. Funciona muy bien para mi nuevo filtro que no necesita ninguna dependencia de autoencendido / inyección.
Aunque combinar # 2 y # 3 funciona bien, me sorprendió que no termine con dos filtros que se apliquen dos veces. Supongo que Spring combina los dos beans como uno cuando llama al mismo método para crear ambos. En caso de que quiera usar el # 3 solo con authowiring, puede AutowireCapableBeanFactory
. Lo siguiente es un ejemplo,
private @Autowired AutowireCapableBeanFactory beanFactory;
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
Filter myFilter = new MyFilter();
beanFactory.autowireBean(myFilter);
registration.setFilter(myFilter);
registration.addUrlPatterns("/myfilterpath/*");
return registration;
}
Los filtros se usan principalmente en archivos de registrador, varían de acuerdo con el registrador que usa en el proyecto. Déjenme explicar por log4j2:
<Filters>
<!-- It prevents error -->
<ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
<!-- It prevents debug -->
<ThresholdFilter level="debug" onMatch="DENY" onMismatch="NEUTRAL" />
<!-- It allows all levels except debug/trace -->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
</Filters>
Los filtros se usan para restringir los datos y utilicé el filtro de umbral más para restringir los niveles de datos en el flujo. Mencioné los niveles que pueden restringirse allí. Para obtener más información, consulte el orden de nivel de log4j2 - Niveles Log4J: ALL> TRACE> DEBUG> INFO> WARN> ERROR> FATAL> OFF
No hay una anotación especial para denotar un filtro de servlet. Usted acaba de declarar un @Bean
de tipo Filter
(o FilterRegistrationBean
). Un ejemplo (agregar un encabezado personalizado a todas las respuestas) está en EndpointWebMvcAutoConfiguration propio de Boot;
Si solo declaras un Filter
, se aplicará a todas las solicitudes. Si también agrega un FilterRegistrationBean
también puede especificar servlets individuales y patrones de url para aplicar.
Nota:
A partir de Spring Boot 1.4, FilterRegistrationBean
no está en desuso y simplemente movió los paquetes de org.springframework.boot.context.embedded.FilterRegistrationBean
a org.springframework.boot.web.servlet.FilterRegistrationBean
Primero, agregue @ServletComponentScan
a su clase SpringBootApplication.
@ServletComponentScan
public class Application {
En segundo lugar, cree un archivo de filtro que amplíe el filtro o la clase de filtro de terceros y agregue @WebFilter
a este archivo como este:
@Order(1) //optional
@WebFilter(filterName = "XXXFilter", urlPatterns = "/*",
dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD},
initParams = {@WebInitParam(name = "confPath", value = "classpath:/xxx.xml")})
public class XXXFilter extends Filter{
Puede usar @WebFilter javax.servlet.annotation.WebFilter en una clase que implemente javax.servlet.Filter
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {}
Luego use @ServletComponentScan para registrarse
Si desea configurar un filtro de terceros, puede usar FilterRegistrationBean
. Por ejemplo, el equivalente de web.xml
<filter>
<filter-name>SomeFilter</filter-name>
<filter-class>com.somecompany.SomeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SomeFilter</filter-name>
<url-pattern>/url/*</url-pattern>
<init-param>
<param-name>paramName</param-name>
<param-value>paramValue</param-value>
</init-param>
</filter-mapping>
Estos serán los dos frijoles en su archivo @Configuration
@Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(someFilter());
registration.addUrlPatterns("/url/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("someFilter");
registration.setOrder(1);
return registration;
}
public Filter someFilter() {
return new SomeFilter();
}
Lo anterior se probó con spring-boot 1.2.3
Si usa Spring Boot + Spring Security, puede hacerlo en la configuración de seguridad.
En el siguiente ejemplo, agrego un filtro personalizado antes de UsernamePasswordAuthenticationFilter (vea todos los filtros predeterminados de Spring Security y su orden ).
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired FilterDependency filterDependency;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(
new MyFilter(filterDependency),
UsernamePasswordAuthenticationFilter.class);
}
}
Y la clase de filtro
class MyFilter extends OncePerRequestFilter {
private final FilterDependency filterDependency;
public MyFilter(FilterDependency filterDependency) {
this.filterDependency = filterDependency;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
// filter
filterChain.doFilter(request, response);
}
}
Usando la anotación @WebFilter, se puede hacer de la siguiente manera:
@WebFilter(urlPatterns = {"/*" })
public class AuthenticationFilter implements Filter{
private static Logger logger = Logger.getLogger(AuthenticationFilter.class);
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.info("checking client id in filter");
HttpServletRequest request = (HttpServletRequest) arg0;
String clientId = request.getHeader("clientId");
if (StringUtils.isNotEmpty(clientId)) {
chain.doFilter(request, response);
} else {
logger.error("client id missing.");
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
Vi muchas respuestas aquí, pero no probé ninguna de ellas. Acabo de crear el filtro como en el siguiente código.
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/Admin")
@Configuration
public class AdminFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("happened");
}
@Override
public void destroy() {
}
}
Y abandonó la aplicación Spring Boot restante tal como estaba.
también puedes hacer un filtro usando @WebFilter e implementa Filter, lo hará.
@Configuration
public class AppInConfig
{
@Bean
@Order(1)
public FilterRegistrationBean aiFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new TrackingFilter());
registration.addUrlPatterns("/**");
registration.setOrder(1);
return registration;
}
@Bean(name = "TrackingFilter")
public Filter TrackingFilter() {
return new TrackingFilter();
}
}
ACTUALIZACIÓN: 2017-12-16:
Hay dos formas simples de hacerlo en Spring boot 1.5.8.RELEASE, no necesita xml.
Primera forma: si no tiene ningún patrón de url espaciador, puede usar @Component de esta manera. El código completo y los detalles están aquí https://www.surasint.com/spring-boot-filter/
@Component
public class ExampleFilter implements Filter{
...
}
Segunda forma: si desea usar el patrón de url, puede usar @WebFilter de esta manera. El código completo y los detalles están aquí https://www.surasint.com/spring-boot-filter-urlpattern/
@WebFilter(urlPatterns = "/api/count")
public class ExampleFilter implements Filter{
...
}
Pero debe agregar esta anotación @ServletComponentScan en su clase de aplicación Spring Boot.
@ServletComponentScan
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
...
}
Tenga en cuenta que @Component es la anotación de Spring, pero @WebFilter no lo es. @WebFiler es la anotación de Servlet 3.
De ambas formas, solo necesitas la dependencia básica de arranque de primavera en pom.xml (no es necesario incluir jaspe incrustado tomcat)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<groupId>com.surasint.example</groupId>
<artifactId>spring-boot-04</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
ADVERTENCIA: La primera manera, si el controlador en el arranque de primavera vuelve a un archivo jsp, la solicitud pasará el filtro dos veces.
Mientras que, de la segunda manera, la solicitud pasará el filtro solo una vez.
Prefiero la segunda vía porque es más similar al comportamiento predeterminado en la especificación de Servlet ( https://docs.oracle.com/cd/E19879-01/819-3669/6n5sg7b0b/index.html )
Verá ver más registro de prueba aquí https://www.surasint.com/spring-boot-webfilter-instead-of-component/