关于在Spring过滤器中修改request的参数值遇到的问题(三)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_29092471/article/details/73556658
  1. 继上一遍为背景

  2. 问题描述:
    成功解密了reqeust中的参数后,在控制层Controller中获取到的参数,是没有解密的参数。例如:在过滤器中修改 参数名为username 的参数值432895328195783915781(一串加密的密文) 为 xiaomin(解密后的明文),在Cotroller中获取到的依然是加密后的密文432895328195783915781。

  3. 问题定位
    百度,没有,心酸,跑不掉,一步一步debugger,终于发现
    在SpringMVC框架中,request到controller层的数据bind(绑定)中,用到该类的方法org.springframework.web.method.annotation.RequestParamMethodArgumentResolver

    @Override
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        MultipartHttpServletRequest multipartRequest =
                WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
        Object arg; // 将被绑定的值
        .
        .
        .
    if (multipartRequest != null) {
                List<MultipartFile> files = multipartRequest.getFiles(name);
                if (!files.isEmpty()) {
                    arg = (files.size() == 1 ? files.get(0) : files);
                }
            }
            if (arg == null) { // 方法走了该判断体
                String[] paramValues = webRequest.getParameterValues(name);
                if (paramValues != null) {
                    arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
                }
            }
    }
    
    

    如上注释,方法在一定条件下走了String[] paramValues = webRequest.getParameterValues(name);这一段代码,debugger发现,
    这段代码走的的真正实现竟然是web容器Tomcat提供的request包装类org.apache.catalina.connector.RequestFacade中的方法。(因为这里的WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class)最后返回了一个Tomcat提供的request包装类)

     @Override
    public String[] getParameterValues(String name) {
    
        if (request == null) {
            throw new IllegalStateException(
                            sm.getString("requestFacade.nullRequest"));
        }
    
        String[] ret = null;
        if (SecurityUtil.isPackageProtectionEnabled()){
            ret = AccessController.doPrivileged(
                new GetParameterValuePrivilegedAction(name));
            if (ret != null) {
                ret = ret.clone();
            }
        } else {
            ret = request.getParameterValues(name);
        }
    
        return ret;
    }

    而该Tomcat的request包装类中的参数,确实是没有解密之前的值。由此猜测(个人猜测,不对的请指点迷津,感激) 1.服务器在接受请求时,Spring和Tomcat各自都创建了一个request的包装类(可以发现都实现了HttpServletRequest接口),在没有修改rquest参数时,这两个包装类几乎一样(指参数值都是一致的),当我在过滤器中修改了Spring的rquest包装类参数值,tomcat的request包装类是没有修改的。2.在SpringMVC的数据绑定中,应为某些原因,需要从tomcat的request包装类中获取参数值。这就导致了上述问题的发生。

    4.解决方案
    在之前的自定义包装类中(继承了ServletRequestWrapper)重写 getParameterValues(String name)方法

    import org.apache.catalina.util.ParameterMap;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.util.Map;
    
    public class ParameterRequestWrapper extends HttpServletRequestWrapper {
    
        private ParameterMap<String, String[]> params;
    
        @SuppressWarnings("all")
        public ParameterRequestWrapper(HttpServletRequest request) {
            super(request);
            params = (ParameterMap) request.getParameterMap();
            // TODO Auto-generated constructor stub
        }
    
        @Override
        public String getParameter(String name) {
            // TODO Auto-generated method stub
            String[] values = params.get(name);
            if (values == null || values.length == 0) {
                return null;
            }
            return values[0];
        }
    
        @Override
        public Map<String, String[]> getParameterMap() {
            // TODO Auto-generated method stub
            return params;
        }
    
        // 就是该方法
        @Override
        public String[] getParameterValues(String name) {
            return params.get(name);
        }
    
        public void addParameter(String name, Object value) {
            if (value != null) {
                params.setLocked(false);
                if (value instanceof String[]) {
                    params.put(name, (String[]) value);
                } else if (value instanceof String) {
                    params.put(name, new String[] { (String) value });
                } else {
                    params.put(name, new String[] { String.valueOf(value) });
                }
                params.setLocked(true);
            }
        }
    }
    

    解决问题,如有不对的地方,还请高人路过指点。

猜你喜欢

转载自blog.csdn.net/baidu_29092471/article/details/73556658