• 【设计模式】装饰者模式解决实际问题


    1.问题描述

    改造一个十年老项目,目的是防sql注入和XSS攻击。

    难点在于前后端传参类型十分复杂,有application/json的,有x-www-form-urlencoded的。

    2.解决思路

    最开始想使用filter,统一拦截下请求体,然后过滤实现。

    但是对于application/json可以这么做,因为就是个json,但是对于x-www-form-urlencoded,它每个请求的key都不一样,不好拿。

    解决问题的思路,找到这两种请求类型的共同点。

    1. 都是放到request里的。
    2. 使用时,application/json的本质是把请求中的流转化为预先设置好的对象,x-www-form-urlencoded的本质是一个放到request里的map。

    根据以上两点,可以使用装饰模式,把request包起来,然后在包装类上对流和map进行处理,然后再把这个包装类当做request放到请求链中。

    3.方案实践

    public class ParameterRequestWrapper extends HttpServletRequestWrapper {
        private final byte[] body;
        private Map<String, Object> parameterMap; 
        
    	public ParameterRequestWrapper(HttpServletRequest request) {
    		super(request);
            //在这里,把request中的流读出来,转成String
    		String sessionStream = getBodyString(request);
            //针对x-www-form-urlencoded,由于后续调用使用的是getParameter这种形式从request的map中取值.
            //针对application/json,我们把这个String转成字符数组。
            if("x-www-form-urlencoded".reqeust.getContentType){
                parameterMap =reqest.getParametes()
            }else if("application/json".reqeust.getContentType){
                 body = sessionStream.getBytes(Charset.forName("UTF-8"));
            }else{
                //根据项目中还出现什么妖魔鬼怪,来决定怎么组织数据结构接request里的值
            }
    		
           
    	}
    
    	@Override
    	public String getParameter(String name) {
    		String parameter = null;
    		String value = null;
    		if(parameterMap != null && parameterMap.get(name) !=null) {
    			value =(String) parameterMap.get(name);
    		}
    		parameter = xssEncode(value);
    		// 过滤sql注入
    		parameter = filterContent(parameter);
    		return parameter;
    	}
    
    	/**
         * 获取请求Body
         *
         * @param request
         * @return
         */
        public String getBodyString(final ServletRequest request) {
            StringBuilder sb = new StringBuilder();
            InputStream inputStream = null;
            BufferedReader reader = null;
            try {
                inputStream = cloneInputStream(request.getInputStream());
                reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (reader != null) {
                    try {
                        reader.close();
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            String ssb = xssEncode(sb.toString());
    		// 过滤sql注入
            ssb = filterContent(ssb);
            System.out.println("application/json的StringBuilder"+sb.toString());
            return ssb;
        }
     
        /**
         * 复制输入流
         */
        public InputStream cloneInputStream(ServletInputStream inputStream) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            try {
                while ((len = inputStream.read(buffer)) > -1) {
                    byteArrayOutputStream.write(buffer, 0, len);
                }
                byteArrayOutputStream.flush();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            return byteArrayInputStream;
        }
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }
     
        @Override
        public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream bais = new ByteArrayInputStream(body);
     
            return new ServletInputStream() {
     
                @Override
                public int read() throws IOException {
                    //@RequestBody会使用这个方法获取流,然后转成Bean给Controller使用,所以要把body写到这里来。
                    return bais.read();
                }
     
                @Override
                public boolean isFinished() {
                    return false;
                }
     
                @Override
                public boolean isReady() {
                    return false;
                }
     
                @Override
                public void setReadListener(ReadListener readListener) {
                }
            };
        }
    
    }
    
    
  • 相关阅读:
    万万没想到,JVM内存结构的面试题可以问的这么难?
    理解JVM运行时数据区域,看这一篇文章就够了
    JVM扫盲:虚拟机内存模型与高效并发
    Java虚拟机难?一文了解JVM
    一篇简单易懂的原理文章,让你把JVM玩弄与手掌之中
    简单理解:JVM为什么需要GC
    一文让你读懂Java类加载机制!
    JVM结构的简单梳理
    深入理解JVM的类加载
    BAT面试必问题系列:JVM的判断对象是否已死和四种垃圾回收算法总结
  • 原文地址:https://www.cnblogs.com/pandaNHF/p/15678154.html
Copyright © 2020-2023  润新知