SpringBoot自定义过滤器的两种方式及过滤器执行顺序

https://www.cnblogs.com/ibigboy/p/11528775.html#_label0_2

https://blog.csdn.net/pzgmissyou/article/details/81170388

第一种 @WebFilter + @ServletComponentScan 注解

1、首先自定义过滤器

如下自定义过滤器 ReqResFilter 必须实现  javax.servlet.Filter。

然后添加注解 @WebFilter(javax.servlet.annotation.WebFilter),urlPatterns 过滤器要过滤的URL规则配置,filterName 过滤器的名称。

@Order(int) 注解,配合 @WebFilter 注解使用,用于多个过滤器时定义执行顺序,值越小越先执行。

记住上面这句话,稍后再说。

package com.wenbei.filter;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

//@Order(1)
@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "reqResFilter")
public class ReqResFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) 
            throws IOException, ServletException {
        log.info("=============自定义过滤器============");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

2、添加 @ServletComponentScan 注解

然后在启动类上加一个注解 @ServletComponentScan 就可以了,然后启动springboot 访问你的接口就会看到打印过滤器里的内容了。

3、多个过滤器如何指定执行顺序?

刚才说了,使用@Order注解指定一个int值,越小越先执行。很多博客文章都是这么说的,但你真正的试了吗?真的可以使用这个注解指定顺序吗?答案是否定的。

经过测试,发现 @Order 注解指定 int 值没有起作用,是无效的。为啥?因为看源码发现 @WebFilter 修饰的过滤器在加载时,没有使用 @Order 注解,而是使用的类名来实现自定义Filter顺序,详细的可以参考这篇或者是这篇

所以这种方式下想定义Filter的顺序,就必须限定 Filter 的类名,比如刚才那个 Filter 叫 ReqResFilter ,加入我们现在新写了一个 Filter 叫 AlibabaFilter ,那么顺序就是 AlibabaFilter > ReqResFilter 。

所以这种方式虽然实现起来简单,只需要注解,但自定义顺序就必须要限定类名,使用类名达到排序效果了。

如果要实现自定义顺序,就用下面这种。

回到顶部

第二种 自定义配置类配置过滤器

1、单个过滤器时

1、自定义配置类加载自定义过滤器 ReqResFilter 

 还是刚才那个自定义过滤器,只不过上面的两个注解都可以去掉了。

@Configuration
public class WebConfig {
    @Bean
    public FilterRegistrationBean reqResFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        ReqResFilter reqResFilter = new ReqResFilter();
        filterRegistrationBean.setFilter(reqResFilter);
     filterRegistrationBean.addUrlPatterns("*.json");//配置过滤规则 
     return filterRegistrationBean;
  } 
}

2、确保 WebConfig 类能被扫描到就可以了,然后启动springboot 访问你的接口就会看到打印过滤器里的内容了。

2、多个过滤器时如何配置

多个过滤器,怎么配置,都写在一个 FilterRegistrationBean 里吗?配置执行顺序怎么配置?过滤器名称怎么配置

新增一个过滤器

如下,新增一个过滤器 ReqResFilter1

public class ReqResFilter1 implements Filter {
    private static Logger logger = LoggerFactory.getLogger(ReqResFilter1.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //获取 filterRegistrationBean.addInitParameter("name","hahahhhaa")设置的参数
        System.out.println("init=============="+filterConfig.getInitParameter("name"));
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("2222222222222222222222222222");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
    }
}

修改配置类

现在我们有两个过滤器 ReqResFilter 和 ReqResFilter1 ,怎么设置执行顺序。请看下面的代码。

这里我们,咋 WebConfig 类里再写一个 reqResFilter1 方法注册新增的这个过滤器。和刚才不同的是我们指定了 多个过滤器的 Order 即执行顺序,ReqResFilter1 的 Order 为2,设置 ReqResFilter  的Order为1。

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean reqResFilter1() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();

        ReqResFilter1 reqResFilter1 = new ReqResFilter1();

        filterRegistrationBean.setFilter(reqResFilter1);
        filterRegistrationBean.addUrlPatterns("*.json");//配置过滤规则
        filterRegistrationBean.addInitParameter("name","hahahhhaa");//设置init参数
        filterRegistrationBean.setName("reqResFilter1");//设置过滤器名称
        filterRegistrationBean.setOrder(2);//执行次序

        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean reqResFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();

        ReqResFilter reqResFilter = new ReqResFilter();

        filterRegistrationBean.setFilter(reqResFilter);

        //配置多个过滤规则
//        List<String> urls = new ArrayList<>();
//        urls.add("/order/*");
//        urls.add("/user/*");
//        filterRegistrationBean.setUrlPatterns(urls);

        filterRegistrationBean.addUrlPatterns("*.json");//配置过滤规则
        filterRegistrationBean.setName("reqResFilter");//设置过滤器名称
        filterRegistrationBean.setOrder(1);//执行次序

        return filterRegistrationBean;
    }
}

另外  filterRegistrationBean.addInitParameter("name","hahahhhaa");//设置init参数 设置的参数在 Filter 的init 方法里的 FilterConfig 对象里可以获取到,即 filterConfig.getInitParameter("name")

另外 filterRegistrationBean.setUrlPatterns(urls); 可以设置多个URL匹配规则,setUrlPatterns接收一个List<String>类型的参数

当不设置 setOrder 次序时,过滤器的执行顺序默认是 Bean 的加载顺序。在当前 WebConfig 类中,先加载的是 reqResFilter1方法 即 ReqResFilter1 过滤器,后加载的是 reqResFilter 方法 即 ReqResFilter 过滤器。

3、SpringBoot注册第三方过滤器

假如我们在项目里引入了第三方的jar,要使用jar里面带的 Filter 的话,如果引用的某个jar包中的过滤器,且这个过滤器在实现时没有使用 @Component 标识为Spring Bean,则这个过滤器将不会生效。此时需要通过java代码去注册这个过滤器。也是使用该种方式进行注册。

备注:自己写的过滤器,做安全漏洞修复

package com.kang.staffinfosystem.filter;

import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ForkJoinPool;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;


//@Order(int) 注解,配合 @WebFilter 注解使用,用于多个过滤器时定义执行顺序,值越小越先执行。
//@Order(1)
//@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "reqResFilter")
public class ReqResFilter implements Filter {
    public final static int DEFAULT_CONTENTLENGTH_LIMIT = 2 * 1024 * 1024;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        System.out.println("=============自定义过滤器============");

        HttpServletRequest httpRequest = (HttpServletRequest)servletRequest;
        HttpServletResponseWrapper httpResponse = new HttpServletResponseWrapper((HttpServletResponse) servletResponse);
        String queryString = httpRequest.getQueryString();
        String urlString = httpRequest.getRequestURI();
        int queryString_length = 0;
        int urlString_length = 0;

        if((queryString != null) && (queryString != "")){
            System.out.println("queryString:"+queryString);
            //过滤特殊字符串
            if(!queryString.equals(filterData(queryString))){
                System.out.println("过滤特殊字符");
                httpResponse.setStatus(404);
                return;
            }
            queryString_length = queryString.length();
        }
        if((urlString != null) && (urlString != "")){
            System.out.println("urlString:"+urlString);
            urlString_length = urlString.length();
        }
        int url_length = queryString_length+urlString_length;
        //url总长度
        System.out.println(url_length);
        if (url_length>2000){
            System.out.println("url长度超出限制>2000");
            httpResponse.setStatus(404);
            return;
        }

        //请求url
        System.out.println(httpRequest.getRequestURI());
        //请求参数长度
        System.out.println(httpRequest.getContentLength());
        if (httpRequest.getContentLength()>DEFAULT_CONTENTLENGTH_LIMIT){
            System.out.println("ContentLength超出限制>"+DEFAULT_CONTENTLENGTH_LIMIT);
            httpResponse.setStatus(404);
            return;
        }
        //请求Referer
        System.out.println(httpRequest.getHeader("Referer"));
        //请求token
        System.out.println(httpRequest.getHeader("csrftoken"));


        System.out.println("=============000000000000============");
        //获取请求头信息
        Enumeration headerNames = httpRequest.getHeaderNames();
        while(headerNames.hasMoreElements()){
            String headerName = (String) headerNames.nextElement();
            String value = httpRequest.getHeader(headerName);
            System.out.println(headerName + "=" + value);
        }
        System.out.println("=============111111111111============");
        //获取cookie信息
        Cookie[] cookies= httpRequest.getCookies();
        if (cookies!=null){
            for (int i = 0; i < cookies.length; i++) {
                System.out.println(cookies[i].getName()+"="+cookies[i].getValue());
            }
        }

        System.out.println("============222222222222=============");
        //获取请求中的参数
        Enumeration pNames = servletRequest.getParameterNames();
        while(pNames.hasMoreElements()){
            String name=(String)pNames.nextElement();
            String value=servletRequest.getParameter(name);
            System.out.println(name + "=" + value);
        }
        if(urlString.startsWith("/main")){
            reGenerateSessionId(httpRequest);
        }

        //添加响应头
        httpResponse.addHeader("Strict-Transport-Security","max-age=31536000; includeSubDomains always");
        httpResponse.addHeader("X-Frame-Options","SAMEORIGIN");
        httpResponse.addHeader("Content-Security-Policy","frame-ancestors 'self'");

        if ((httpRequest.getHeader("X-HTTP-Method")!=null && !httpRequest.getHeader("X-HTTP-Method").isEmpty())
                ||(httpRequest.getHeader("X-HTTP-Method-Override")!=null && !httpRequest.getHeader("X-HTTP-Method-Override").isEmpty())
                ||(httpRequest.getHeader("X-Method-Override")!=null && !httpRequest.getHeader("X-Method-Override").isEmpty())
                ||(httpRequest.getHeader("X-Scan-Memo")!=null && !httpRequest.getHeader("X-Scan-Memo").isEmpty())){
            System.out.println("包含禁用的请求头");
            httpResponse.setStatus(404);
            return;
        }

        filterChain.doFilter(servletRequest,servletResponse);

    }

    @Override
    public void destroy() {

    }

    /**
     * 重置sessionid,原session中的数据自动转存到新session中
     * @param request
     */
    public static void reGenerateSessionId(HttpServletRequest request){

        HttpSession session = request.getSession();

        //首先将原session中的数据转移至一临时map中
        Map<String,Object> tempMap = new HashMap<String, Object>();
        Enumeration<String> sessionNames = session.getAttributeNames();
        while(sessionNames.hasMoreElements()){
            String sessionName = sessionNames.nextElement();
            tempMap.put(sessionName, session.getAttribute(sessionName));
        }

        //注销原session,为的是重置sessionId
        session.invalidate();

        //将临时map中的数据转移至新session
        session = request.getSession();
        for(Map.Entry<String, Object> entry : tempMap.entrySet()){
            session.setAttribute(entry.getKey(), entry.getValue());
        }
    }
    //特殊字符过滤
    public String filterData(String str) throws PatternSyntaxException {
        // 只允许字母和数字 // String regEx = "[^a-zA-Z0-9]";
        // 清除掉所有特殊字符
        String regEx = "[`~!@#$%^*()+|{}':;',\\[\\].<>/?~!@#¥%……*()——+|{}【】‘;:”“’。,、?]";
        //String regEx = "[`~!@#$%^&*()+=|{}';',\\[\\]<>?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.replaceAll("").trim();
    }
}

Guess you like

Origin blog.csdn.net/qq_40197728/article/details/120158837