spring学习(三十四)--过滤器

一 过滤器和拦截器的区别

(1)过滤器:

依赖于servlet容器,是JavaEE标准,是在请求进入容器之后,还未进入Servlet之前进行预处理,并且在请求结束返回给前端这之间进行后期处理。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作。过滤器可以简单理解为“取你所想取”,忽视掉那些你不想要的东西,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等

spring中过滤器实现有两种方式:

1、实现org.springframework.web.filter.OncePerRequestFilter接口。

2、实现javax.servlet.Filter接口。

(2)拦截器:

拦截器不依赖与servlet容器,依赖于web框架。在SpringMVC中就是依赖于SpringMVC框架,在SSH框架中,就是依赖于Struts框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用spring的依赖注入(DI)获取IOC容器中的各个bean,进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,即⑴请求还没有到controller层时进行拦截,⑵请求走出controller层次,还没有到渲染时图层时进行拦截,⑶结束视图渲染,但是还没有到servlet的结束时进行拦截。对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理,拦截器功在对请求权限鉴定方面确实很有用处。它可以简单理解为“拒你所想拒”。

多个过滤器与拦截器的代码执行顺序

如果在一个项目中仅仅只有一个拦截器或者过滤器,那么我相信相对来说理解起来是比较容易的。但是我们是否思考过:如果一个项目中有多个拦截器或者过滤器,那么它们的执行顺序应该是什么样的?或者再复杂点,一个项目中既有多个拦截器,又有多个过滤器,这时它们的执行顺序跟xml文件中定义的先后关系有关。

1、定义四个过滤器

package myFilters;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
 
public class XSSFilter extends OncePerRequestFilter {
    /**
     * XSS过滤
     */
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        if (StringUtils.isNotBlank(requestURI)) {
            requestURI = requestURI.replace(request.getContextPath(), "");
        }

        EscapeScriptwrapper escapeScriptwrapper = new EscapeScriptwrapper(request);
        filterChain.doFilter(escapeScriptwrapper, response);
    }
    
    /**
     * 将传递进来的不需要过滤得路径集合的字符串格式化成一系列的正则规则
     * @param str 不需要过滤的路径集合
     * @return 正则表达式规则
     * */
    private String getRegStr(String str){
        if(StringUtils.isNotBlank(str)){
            String[] excludes = str.split(";");  //以分号进行分割
            int length = excludes.length;
            for(int i=0;i<length;i++){
                String tmpExclude = excludes[i];
                //对点、反斜杠和星号进行转义
                tmpExclude = tmpExclude.replace("\\", "\\\\").replace(".", "\\.").replace("*", ".*");
 
                tmpExclude = "^" + tmpExclude + "$";
                excludes[i] = tmpExclude;
            }
            return StringUtils.join(excludes, "|");
        }
        return str;
    }
    
    /**
     * 继承HttpServletRequestWrapper,创建装饰类,以达到修改HttpServletRequest参数的目的
     * */
    private class EscapeScriptwrapper extends HttpServletRequestWrapper{
        private Map<String, String[]> parameterMap;  //所有参数的Map集合
        public EscapeScriptwrapper(HttpServletRequest request) {
            super(request);
            parameterMap = request.getParameterMap();
        }
        
        //重写几个HttpServletRequestWrapper中的方法
        /**
         * 获取所有参数名
         * @return 返回所有参数名
         * */
        @Override
        public Enumeration<String> getParameterNames() {
            Vector<String> vector = new Vector<String>(parameterMap.keySet());
            return vector.elements();
        }
        
        /**
         * 获取指定参数名的值,如果有重复的参数名,则返回第一个的值
         * 接收一般变量 ,如text类型
         * 
         * @param name 指定参数名
         * @return 指定参数名的值
         * */
        @Override
        public String getParameter(String name) {
            String[] results = parameterMap.get(name);
            if(results == null || results.length <= 0)
                return null;
            else{
                return escapeXSS(results[0]);
            }
        }
 
        /**
         * 获取指定参数名的所有值的数组,如:checkbox的所有数据
         * 接收数组变量 ,如checkobx类型
         * */
        @Override
        public String[] getParameterValues(String name) {
            String[] results = parameterMap.get(name);
            if(results == null || results.length <= 0)
                return null;
            else{
                int length = results.length;
                for(int i=0;i<length;i++){
                    results[i] = escapeXSS(results[i]);
                }
                return results;
            }
        }
        
        /**
         * 过滤字符串中的js脚本
         * 解码:StringEscapeUtils.unescapeXml(escapedStr)
         * */
        private String escapeXSS(String str){
            str = StringEscapeUtils.escapeXml(str);
            
            Pattern tmpPattern = Pattern.compile("[sS][cC][rR][iI][pP][tT]");
            Matcher tmpMatcher = tmpPattern.matcher(str);
            if(tmpMatcher.find()){
                str = tmpMatcher.replaceAll(tmpMatcher.group(0) + "\\\\");
            }
            return str;
        }
    }
 
}

ip白名单过滤器

package myFilters;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
 

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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import utils.PropertiesUtil;
 
public class RequestIPFilter implements Filter{
 
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
         
    }
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub
        String allowIps="";
        try {
            allowIps = PropertiesUtil.getProperties("whistListIp");
        } catch (Exception e) {
            e.printStackTrace();
        }
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        if(allowIps.isEmpty()){
            chain.doFilter(req, res);
        }else{
            String[] ips = allowIps.split(";");
            Map<String,String> map = new HashMap<String,String>();
            for(int i=0;i<ips.length;i++){
                map.put(ips[i], ips[i]);
            }
            String ip = request.getRemoteAddr();
            System.out.println("请求ip:" + ip);
            if(map.containsKey(ip)){
                chain.doFilter(req, res);
            }else{
                response.sendError(response.SC_UNAUTHORIZED, request.getRequestURI());
            }
        }
    }
 
    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
         
    }
 
}

调用时长过滤器

package myFilters;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestTimeFilter implements Filter{
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(String.format("----%s接收请求时间:%s-------", request.getRequestURL(), df.format(new Date())));
        long begin = System.currentTimeMillis();
        filterChain.doFilter(req, res);
        System.out.println(String.format("-----%s处理请求的时间ms:%s------", request.getRequestURL(), System.currentTimeMillis()-begin));
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
        
    }

}

改变请求参数过滤器

package myFilters;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Vector;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.filter.OncePerRequestFilter;
 
public class ModifyParametersFilter extends OncePerRequestFilter {
 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        ModifyParametersWrapper mParametersWrapper = new ModifyParametersWrapper(request);
        filterChain.doFilter(mParametersWrapper, response);
    }
 
    /**
     * 继承HttpServletRequestWrapper,创建装饰类,以达到修改HttpServletRequest参数的目的
     */
    private class ModifyParametersWrapper extends HttpServletRequestWrapper {
        private Map<String, String[]> parameterMap; // 所有参数的Map集合
 
        public ModifyParametersWrapper(HttpServletRequest request) {
            super(request);
            parameterMap = request.getParameterMap();
        }
 
        // 重写几个HttpServletRequestWrapper中的方法
        /**
         * 获取所有参数名
         * 
         * @return 返回所有参数名
         */
        @Override
        public Enumeration<String> getParameterNames() {
            Vector<String> vector = new Vector<String>(parameterMap.keySet());
            return vector.elements();
        }
 
        /**
         * 获取指定参数名的值,如果有重复的参数名,则返回第一个的值 接收一般变量 ,如text类型
         * 
         * @param name
         *            指定参数名
         * @return 指定参数名的值
         */
        @Override
        public String getParameter(String name) {
            String[] results = parameterMap.get(name);
            if (results == null || results.length <= 0)
                return null;
            else {
                System.out.println("修改之前: " + results[0]);
                return modify(results[0]);
            }
        }
 
        /**
         * 获取指定参数名的所有值的数组,如:checkbox的所有数据 
         * 接收数组变量 ,如checkobx类型
         */
        @Override
        public String[] getParameterValues(String name) {
            String[] results = parameterMap.get(name);
            if (results == null || results.length <= 0)
                return null;
            else {
                int length = results.length;
                for (int i = 0; i < length; i++) {
                    System.out.println("修改之前2: " + results[i]);
                    results[i] = modify(results[i]);
                }
                return results;
            }
        }
 
        /**
         * 自定义的一个简单修改原参数的方法,即:给原来的参数值前面添加了一个修改标志的字符串
         * 
         * @param string
         *            原参数值
         * @return 修改之后的值
         */
        private String modify(String string) {
            return "Modified: " + string;
        }
    }
 
}

在web.xml中定义这四个过滤器,工程启动后,将根据web.xml定义的顺序一次执行这四个过滤器

    <!-- XSS攻击过滤器(这个过滤的规则有问题,此处只做示例),在web.xml文件中将该过滤器放在最前面或者是字符编码过滤器之后: -->
    <filter>
        <filter-name>xssFilter</filter-name>
        <filter-class>myFilters.XSSFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>xssFilter</filter-name>
        <url-pattern>*</url-pattern>
        <!-- 直接从客户端过来的请求以及通过forward过来的请求都要经过该过滤器 -->
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    
    <!-- ip白名单过滤器 -->
    <filter>
        <filter-name>ipFilter</filter-name>
        <filter-class>myFilters.RequestIPFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ipFilter</filter-name>
        <url-pattern>*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

    <!-- 打印请求时间过滤器 -->
    <filter>
        <filter-name>timeFilter</filter-name>
        <filter-class>myFilters.RequestTimeFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>timeFilter</filter-name>
        <url-pattern>*</url-pattern>
    </filter-mapping>
    
    <!-- 改变request参数过滤器 -->
    <filter>
        <filter-name>modifyParametersFilter</filter-name>
        <filter-class>myFilters.ModifyParametersFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>modifyParametersFilter</filter-name>
        <url-pattern>*</url-pattern>
    </filter-mapping>

猜你喜欢

转载自www.cnblogs.com/gllegolas/p/11863673.html